Linux——进程信号
linux——进程间通信system V消息队列-CSDN博客
文章目录
-
目录
文章目录
生活中的信号
二、Linux下的信号
1.kill -l查看信号列表
2.从硬件角度了解型号
三、信号的产生
1、键盘组合键
2.kill函数
3、系统调用
总结
生活中的信号
- 交通信号灯案例
- 交通信号灯可以看作是一种 “信号” 机制。在十字路口,交通信号灯(类比操作系统)向不同方向的车辆和行人(类比进程)发送信号。例如,红灯信号就像是一个 “停止” 信号(类似于 SIGSTOP 信号,暂停进程)。当红灯亮起时,车辆和行人需要停止前进,这就如同进程接收到信号后暂停执行。绿灯信号则是一个 “运行” 信号(类似于 SIGCONT 信号,继续进程),车辆和行人可以通行。
- 学校铃声案例
- 在学校里,铃声是一种信号。上课铃响就如同给学生和老师(进程)发送一个 “开始上课” 的信号。学生和老师听到铃声后,会结束课间活动状态,开始进入课堂教学和学习状态。下课铃响则是一个 “下课” 信号,让师生结束课堂进程,开始课间休息。
- 智能手机通知案例
- 智能手机的通知系统也类似于进程信号。当你在使用手机上的一个应用程序(进程),比如正在阅读电子书,此时有新的短信进来。系统会发送一个通知信号(类似于操作系统向进程发送信号),手机屏幕上会弹出短信通知,还可能伴有声音或震动。你可以选择暂时忽略这个信号(继续阅读电子书),或者响应这个信号(打开短信应用查看短信),这就如同进程可以选择捕获并处理信号或者忽略信号。
一、信号是什么?
- 在计算机操作系统中,进程信号是一种异步通知机制。它用于通知进程发生了某个事件。就好像在一个工厂(操作系统)里,有许多生产线(进程)在工作,信号就像是一个警报系统。当某个特殊情况发生时(比如设备故障、原材料用完等),警报(信号)就会被触发,通知对应的生产线(进程)做出相应的反应。
- 信号可以由操作系统发送给进程,也可以由进程发送给其他进程。常见的信号包括 SIGINT(通常由用户在终端中按下 Ctrl + C 产生,用于终止一个正在运行的前台进程)、SIGTERM(用于请求一个进程正常终止)、SIGKILL(强制终止一个进程,这个信号不能被进程捕获或忽略)等。
- 信号是进程之间事件异步通知的一种方式,属于软中断。
- 注意
- Ctrl-C 产生的信号只能发给前台进程。一个命令后面加个&可以放到后台运行,这样Shell不必等待进程 结束就可以接受新的命令,启动新的进程。
- Shell可以同时运行一个前台进程和任意多个后台进程,只有前台进程才能接到像 Ctrl-C 这种控制键产生 的信号。
- 前台进程在运行过程中用户随时可能按下 Ctrl-C 而产生一个信号,也就是说该进程的用户空间代码执行 到任何地方都有可能收到 SIGINT 信号而终止,所以信号相对于进程的控制流程来说是异步 (Asynchronous)的。
二、Linux下的信号
1.kill -l查看信号列表
我们认识9号信号SIGKILL这个信号,这就信号在我们杀进程的时候进程使用。
每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中找到,例如其中有定 义 #define SIGINT 2
编号34以上的是实时信号,本章只讨论编号34以下的信号,不讨论实时信号。这些信号各自在什么条件下 产生,默认的处理动作是什么,在signal(7)中都有详细说明: man 7 signal
34—64号信号都是实时信号,我们先不做研究
当我们查看库函数
man signal时,我们可以看到函数作用是将我们特定进程对于信号的处理的动作。
接口参数:signum:为指定记号指令
函数参数sighandler_t 是什么类型呢
我们看到它是一个函数指针,返回值是void 参数是int 函数名为sighandler_t
写个代码演示一下
#include<iostream>
#include<unistd.h>
#include<signal.h>
using namespace std;
void handler(int signum)
{
cout<< "process get a signal: " << signum <<endl;
}
int main()
{
signal(2,handler);
while(true)
{
cout<<"I am a process, pid: "<<getpid()<<endl;
}
return 0;
}
这就是我们发送2号信号,也就是我们常用的ctrl+c指令,强制终止的指令
2.从硬件角度了解型号
我们从键盘上输入一个信号都好都会存储到键盘文件中,我们学习io时,我们知道fd为0的文件就是键盘文件,然后带操作系统加载到了内存缓冲区当中,但是我们的进程不会制动去读取,那么在我们键盘输入时,键盘会发送一个硬件中断信号,这个信号经过中断单元向cpu发送一个高低电平,而cup中的寄存器会将这个电信号存储起来,我们学习数字电路时,我们知道寄存器可以存储0或者1的电信号,然后多个寄存器就将这个键盘信号存取下来了,然后让操作系统去中断向量表中读取方法的地址。
三、信号的产生
1、键盘组合键
ctrl+c 为2号信号 SIGINT
ctrl+\ 为3号信号 SIGQUIT
2.kill函数
参数pid为需要向那个进程发送信号,sig为信号
代码演示kill
#include <iostream>
#include <unistd.h>
#include <signal.h>
using namespace std;
void handler(int signum)
{
cout << "process get a signal: " << signum << endl;
}
int main()
{
signal(2, handler);
int cnt=0;
while (true)
{
cout << "I am a process, pid: " << getpid() << endl;
sleep(1);
cnt++;
if (cnt % 2 == 0)
{
kill(getpid(), 2);
}
}
return 0;
}
因为我们将2号指令给修改了,所以不是默认的终止进程
手搓kill指令
#include <iostream>
#include <unistd.h>
#include <signal.h>
using namespace std;
void handler(int signum)
{
cout << "process get a signal: " << signum << endl;
}
void Usage(string proc)
{
cout << "Usage:\n\t" << proc << " signum pid\n\n";
}
int main(int argc, char *argv[])
{
if (argc != 3)
{
Usage(argv[0]);
exit(1);
}
int signum = stoi(argv[1]);
pid_t pid = stoi(argv[2]);
int n = kill(pid, signum);
if(n == -1)
{
perror("kill");
exit(2);
}
return 0;
}
3、系统调用
raise接口
他就等于kill(getpid,sig)函数
参数也就是我们的信号
代码演示
#include <iostream>
#include <unistd.h>
#include <signal.h>
using namespace std;
void handler(int signum)
{
cout << "process get a signal: " << signum << endl;
}
int main()
{
signal(2,handler);
int cnt = 0;
while (true)
{
cout << "I am a process, pid: " << getpid() << endl;
if (cnt % 2 == 0)
{
raise(2);
sleep(1);
}
}
return 0;
}
abort接口
它等于kill(getpid,SIGABRT)
这些都是信号的产生方式,无论信号是如何产生的,最终都是谁发送的呢?
总结
- 信号是操作系统中用于进程间通信或者操作系统与进程间通信的一种异步事件通知机制。它就像是一种 “软件中断”,进程在运行过程中,不需要主动去检查某个事件是否发生,而是当事件发生时(信号产生),操作系统会将信号发送给相关的进程。
- 信号有多种类型,每种类型代表不同的事件,如终止信号(
SIGTERM
、SIGKILL
)、暂停信号(SIGSTOP
、SIGTSTP
)、继续信号(SIGCONT
)等。进程可以根据信号的类型来采取不同的响应方式,例如,进程可以选择捕获信号并执行自定义的信号处理函数来处理信号,也可以选择忽略某些信号(部分信号不能被忽略,如SIGKILL
)。 - 信号的产生来源广泛,包括用户操作、硬件异常、软件事件和定时器等。这些信号的产生和处理机制帮助操作系统更好地管理进程,协调各个进程之间的关系,以及让进程能够及时响应各种内外部事件,从而保证系统的稳定性和可靠性。