Linux -- 初识信号
目录
什么是信号?
如何使用信号?
代码:
testSig.cc
makefile:
验证:
2号信号:
9号信号:
建立对信号的认识:
信号的处理
自定义信号的处理方式:
signal 函数:
参数
返回值
代码1(以2号信号为例):
验证1:
代码2:
验证2:
编辑
忽略信号:
代码:
验证:
什么是信号?
信号是 Linux 系统提供的、让用户(进程)给其他进程发送异步信号的一种方式,用于通知进程发生了某个事件。
异步:一种编程模型或操作模式,在这种模式下,任务的执行不会阻塞或等待其他任务完成,而是独立进行,并且可以在任务完成时通过回调、事件或其他机制通知主程序。
指令 kill -l 可以查看 Linux 中的信号,可以注意到,没有 0号、32号、33号信号,且从 34号信号开始,信号名字中都带有 RT:
如何使用信号?
下面用简单的代码来认识一些常见的信号:
代码:
testSig.cc
#include<iostream>
using namespace std;
#include<unistd.h>
#include<sys/types.h>
int main()
{while(1){cout<<" I am activing ... pid: "<<getpid()<<endl;sleep(1);}return 0;
}
makefile:
testSig:handlerSig.ccg++ -o $@ $^ -std=c++11.PHONY:clean
clean:rm -f testSig
验证:
指令 kill -signal pid 就可以向指定进程发送信号。
2号信号:
2号信号在Linux系统中对应的是
SIGINT
(Interrupt Signal),通常被称为中断信号,用于请求中断正在运行的程序。
可以看出,死循环的进程在收到信号后结束死循环,进程终止:
指令必须带 pid,不能是进程名:
指令中的 -signal 可以是数字,也可以是信号的名字(即宏定义):
9号信号:
9号信号在Linux系统中对应的是
SIGKILL
信号,是一个强制终止信号,用于立即终止进程。
进程收到信号后,会打印 "Killed":
建立对信号的认识:
初步了解了什么是信号后,我们需要建立以下对信号的认识:
1、还没有向指定进程发送信号时,进程已经知道收到信号时,该怎么处理了;
2、信号能够被识别出来,也就是说,编写内核的才程序员提前给进程设定好了识别特定信号的方式;
3、进程收到信号时,如果进程正在处理更重要的事情,进程可以暂时不处理收到的信号,但是进程必须临时保存该信号!
4、进程收到信号时,可以不立即处理,可以在合适的时候处理;
5、信号可以随时产生!我们无法预测信号什么时候发送,所以信号是异步发送的!
以上的认识可以结合日常生活的例子理解,比如,把早起的闹钟设为一种信号,我们在闹钟响之前,已经知道听到闹钟时该怎么处理这个信号了,那就是起床,我们也可以先不起床,等到想起床的时候再起床,而且,我们在睡梦中无法预测闹钟什么时候会响。
信号的处理
从上面两个信号的例子可以看出,进程收到不同的信号后,有不同的处理方式,而以上的信号处理方式,是信号处理的默认动作,我们还可以捕捉信号,自定义信号的处理方式,或者忽略信号!
自定义信号的处理方式:
signal 函数:
signal
函数是 Linux 系统中用于设置信号处理函数的简单接口。它允许你指定当进程接收到某个信号时应调用哪个函数,而不是默认的信号处理方式。
#include <signal.h>void (*signal(int signum, void (*handler)(int)))(int);
参数
signum: 要处理的信号编号。
handler: 信号处理函数的指针,类型为
void (*)(int)
。这个函数会在接收到指定信号时被调用,也就是说,如果进程没有收到指定信号,handler 函数将永远不会被调用!
返回值
成功: 返回之前的信号处理函数指针。
失败: 返回
SIG_ERR
,此时errno
会被设置为相应的错误码。
代码1(以2号信号为例):
#include<iostream>
using namespace std;
#include<unistd.h>
#include<sys/types.h>
#include<signal.h>void handler(int signo)
{cout<<" I got a signal,signo:"<<signo<<endl;
}
int main()
{signal(SIGINT,handler);while(1){cout<<" I am activing ... pid: "<<getpid()<<endl;sleep(1);}return 0;
}
验证1:
代码2:
在代码1的基础上,设置了退出码:
#include<iostream>
using namespace std;
#include<unistd.h>
#include<sys/types.h>
#include<signal.h>void handler(int signo)
{cout<<" I got a signal,signo:"<<signo<<endl;exit(100);
}
int main()
{signal(SIGINT,handler);while(1){cout<<" I am activing ... pid: "<<getpid()<<endl;sleep(1);}return 0;
}
验证2:
进程结束后,当我们查看退出码时,退出码为100:
忽略信号:
只需要在 signal 的 handler 参数传入 SIG_IGN,即可忽略指定的信号!
代码:
#include<iostream>
using namespace std;
#include<unistd.h>
#include<sys/types.h>
#include<signal.h>int main()
{signal(SIGINT,SIG_IGN);while(1){cout<<" I am activing ... pid: "<<getpid()<<endl;sleep(1);}return 0;
}
验证:
可以看出,当我们向进程发送 2号信号时,进程忽略了 2号信号,不做任何处理,于是发送 9号信号终止进程!