目录
一、信号的概念
信号是UNIX系统响应某些状况而产生的事件,进程在接收到信号时会采取相应的行动,信号是因为某些错误条件而产生的,比如内存段冲突、浮点处理器错误或者非法指令等。它们由shell和终端管理器产生以引起中断。信号的目的是为了通知做某件事,就比如早上的闹钟通知你起床,闹钟就起到一个信号的作用。
在linux下可以通过 kill -l 查看所有的信号
之前提到过通过 kill -9 进程ID,可以把该ID所属的进程结束掉。学习了信号这个概念,可以将这条命令理解为发送第9个信号给该ID所属的进程,通知他去做某件事。通过上图所示第9个信号为SIGKILL,也就是发送停止进程的信号给该ID所属的进程,通知它停下来,也就是所谓的“杀死”进程。
编号为1-31的为不可靠信号,34-64的为可靠信号。连续不间断发送信号,信号会丢失的为不可靠信号,连续不间断发送信号,信号不会丢失的为可靠信号。
二、signal()库函数
如果想让程序能够处理信号,可以使用 signal库函数,要引入头文件<signal.h>。在linux终端下输入命令 man signal来查看他的函数原型
可以看到,signal()函数的第一个参数signum是信号编号,也就是 kill -l 能够查询到的所有信号,第二个参数sighandler是一个函数指针。
准备捕捉或屏蔽的信号由参数signum给出,接收到指定信号时将要调用的函数由sighandler给出。sighandler这个函数必须有一个int类型的参数(即接收到的信号代码),函数本身的类型是void,sighandler也可以是下面两个特殊值:SIG_IGN(屏蔽该信号),SIG_DFL (恢复默认行为)。
通俗的说signal()库函数的作用是将某个信号和某个函数绑定起来,当这个信号被发送出来,就去做绑定的这个函数的业务。Qt的信号与槽机制就是通过借鉴这种方式来实现的。
三、kill()函数
1、函数作用
kill函数的作用是把参数sig给定的信号发送给标识号为pid的进程。如果该信号通过sinal()和某个函数绑定起来,那么就暂时中断这个进程,去做绑定的这个函数的业务,做完这个函数的业务,进程继续运行。
要想发送一个信号,发送者进程必须拥有相应的权限。这通常意味着两个进程必须拥有同样的用户ID。
2、函数原型
int kill(pid_t pid, int sig);
参数:
pid:进程ID
sig:某个信号
返回值:
成功返回0,出错返回-1。
四、可靠与不可靠信号
下面通过一段代码来验证可靠信号和不可靠信号
#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
void signalfunction(int i);
int main()
{
int pid = 0;
int status = 0;
//将信号和函数绑定在一起
signal(SIGUSR1, signalfunction);
pid = fork();
if (pid == 0)//子进程
{
while(1)
{
cout << "子进程运行中 pid = " << getpid() << endl;
sleep(1);
}
}
else if(pid > 0)//父进程
{
sleep(3);//先让子进程先处理业务,测试kill函数
for (int i = 1; i <= 5; i++)
{
cout << "父进程给子进程发送第 " << i << " 个信号" << endl;
kill(pid, SIGUSR1);//给子进程发送信号
}
sleep(3);//延时3秒
kill(pid, SIGKILL);//给子进程发送停止信号
waitpid(pid, &status, 0);//等待子进程结束,防止子进程托孤
cout << "子进程结束" << endl;
}
return 0;
}
void signalfunction(int i)
{
cout << "函数被调用了 i = " << i << endl;
}
编号为10的信号(SIGUSR1)和编号为12的信号(SIGUSR2)都是用户信号,程序员可以使用他,同时这两个信号都是不可靠信号。
上面的这段代码父进程通过一个for循环循环发送5次信号(SIGUSR1),而该信号(SIGUSR1)通过signal(SIGUSR1, signalfunction)和signalfunction()函数绑定起来,也就是说发送一次信号就会调用一次这个signalfunction()函数。控制台输出如下:
可以发现父进程发送了5次信号,可是绑定的函数才执行一次,也就是出现了信号丢失的现象,印证了:连续不间断发送信号,信号会丢失的为不可靠信号,编号为1-31的都是不可靠信号。同时可以发现调用的函数打印的int类型的值正好是该不可靠信号(SIGUSR1)的编号10。
如果将signal(SIGUSR1, signalfunction)改为signal(SIGRTMIN, signalfunction),发送信号kill(pid, SIGUSR1)改为kill(pid, SIGRTMIN)来继续测试,控制台输出如下:
可以发现父进程发送了5次信号,绑定的函数也执行了5次,也就是信号并没有丢失,印证了:连续不间断发送信号,信号不会丢失的为可靠信号,编号为34-64的都是可靠信号。调用的函数打印的int类型的值也正好是该可靠信号(SIGRTMIN)的编号34。
五、总结
1、signal()函数可以将某个信号和某个函数绑定起来。
2、kill()函数可以发送某个信号给某个ID的子进程,并暂时中断该子进程,转去处理这个信号通过signal()函数绑定的函数业务。
3、编号为1-31的都是不可靠信号,34-64的都是可靠信号。连续不间断发送信号时不可靠信号会出现信号丢失的现象,而可靠信号不会出现这个现象。
原创不易,转载请标明出处。
对您有帮助的话可以点赞收藏+关注,会持续更新的(嘻嘻)。