linux远程开发|linux远程开发——信号的使用(信号绑定和发送)

目录
一、信号的概念
二、signal()库函数
三、kill()函数
1、函数作用
2、函数原型
四、可靠与不可靠信号
五、总结

一、信号的概念 信号是UNIX系统响应某些状况而产生的事件,进程在接收到信号时会采取相应的行动,信号是因为某些错误条件而产生的,比如内存段冲突、浮点处理器错误或者非法指令等。它们由shell和终端管理器产生以引起中断。信号的目的是为了通知做某件事,就比如早上的闹钟通知你起床,闹钟就起到一个信号的作用。
在linux下可以通过 kill -l 查看所有的信号
linux远程开发|linux远程开发——信号的使用(信号绑定和发送)
文章图片

之前提到过通过 kill -9 进程ID,可以把该ID所属的进程结束掉。学习了信号这个概念,可以将这条命令理解为发送第9个信号给该ID所属的进程,通知他去做某件事。通过上图所示第9个信号为SIGKILL,也就是发送停止进程的信号给该ID所属的进程,通知它停下来,也就是所谓的“杀死”进程。
编号为1-31的为不可靠信号,34-64的为可靠信号。连续不间断发送信号,信号会丢失的为不可靠信号,连续不间断发送信号,信号不会丢失的为可靠信号。

二、signal()库函数 如果想让程序能够处理信号,可以使用 signal库函数,要引入头文件。在linux终端下输入命令 man signal来查看他的函数原型
linux远程开发|linux远程开发——信号的使用(信号绑定和发送)
文章图片

可以看到,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:某个信号
【linux远程开发|linux远程开发——信号的使用(信号绑定和发送)】返回值:
成功返回0,出错返回-1。
四、可靠与不可靠信号 下面通过一段代码来验证可靠信号和不可靠信号
#include #include #include #include #include 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()函数。控制台输出如下:
linux远程开发|linux远程开发——信号的使用(信号绑定和发送)
文章图片

可以发现父进程发送了5次信号,可是绑定的函数才执行一次,也就是出现了信号丢失的现象,印证了:连续不间断发送信号,信号会丢失的为不可靠信号,编号为1-31的都是不可靠信号。同时可以发现调用的函数打印的int类型的值正好是该不可靠信号(SIGUSR1)的编号10。
如果将signal(SIGUSR1, signalfunction)改为signal(SIGRTMIN, signalfunction),发送信号kill(pid, SIGUSR1)改为kill(pid, SIGRTMIN)来继续测试,控制台输出如下:
linux远程开发|linux远程开发——信号的使用(信号绑定和发送)
文章图片

可以发现父进程发送了5次信号,绑定的函数也执行了5次,也就是信号并没有丢失,印证了:连续不间断发送信号,信号不会丢失的为可靠信号,编号为34-64的都是可靠信号。调用的函数打印的int类型的值也正好是该可靠信号(SIGRTMIN)的编号34。

五、总结 1、signal()函数可以将某个信号和某个函数绑定起来。
2、kill()函数可以发送某个信号给某个ID的子进程,并暂时中断该子进程,转去处理这个信号通过signal()函数绑定的函数业务。
3、编号为1-31的都是不可靠信号,34-64的都是可靠信号。连续不间断发送信号时不可靠信号会出现信号丢失的现象,而可靠信号不会出现这个现象。

原创不易,转载请标明出处。
对您有帮助的话可以点赞收藏+关注,会持续更新的(嘻嘻)。

    推荐阅读