Linux:信号(一)
1. 信号是什么
信号的概念
Linux中信号(Signal)是进程间通信的一种基本机制,用于通知进程发生了某种事件或异常。信号是异步的,可能由操作系统、其他进程或进程自身触发。
kill -l 指令查看所有的信号
上面的SIGHUP、SIGINT本质就是define宏定义,上面的1~31是普通信号,34~64信号是实时信号。
信号的基本作用
1. 通知进程某个事件(终止请求,错误处理等)
2. 允许进程对其他进程或操作系统内核发送简单消息
3. 处理异常(段错误,除0错误等等)
基本结论
1. 进程在信号没有产生的时候就知道信号如何处理了。
2. 信号的处理,不是立即处理,而是等到合适的时候再处理
3. 进程早已经内置了对于信号的识别和处理方式。
4. 给进程产生信号的信号源很多
2. 信号的产生
产生信号的方式有很多
为了验证信号的产生我们,需要使用下面的函数
定义:自己设置signum(第一个参数)信号的处理方式
函数声明与头文件
#include
typedef void (*sighandler_t)(int); sighandler_t signal(int signum,sighandler_t handler); 参数:
signum:是几号信号即信号的名称。
handler:函数指针,一个返回值类型为void 参数为int的函数
返回值:旧的信号处理函数,(函数指针)
(1). 键盘产生信号
按键 | 功能 |
ctrl+c | 向进程发送SIGINT信号,终止进程。 |
ctrl+ | 向进程发送SIGQUIT信号,终止进程 |
ctrl+z | 向进程发送SIGSTP信号,暂停进程的执行 |
以ctrl+c为例
ctrl+c就是给目标进程发送信号(中断信号),默认情况下导致进程终止掉。
ctrl+c只能终止前台进程无法终止后台进程。(在Linux中,前台进程只能有一个,后台进程可以为多个)
./test 前台进程
./test & 后台进程
我们可以看到ctrl+c没有终止进程,通过指令 kill -9 进程id 才将进程杀掉
在程序执行时也可以切换前后台程序
jobs 指令查看所有后台任务
fg 任务号 :将指定的进程变为前台进程
ctrl+z :暂停当前进程。然后把进程切换到后台。
bg 任务号 :让进程恢复运行变为后台进程
我们看看被signal函数修改了处理方法(新处理方法不终止进程)的2号信号能否终止进程
#include
#include
#include
#include
int cnt=0;
void handlerSig(int sig)
{
std::cout<<"信号获取成功 ->"<
执行结果如下,ctrl+c并不能终止进程了
(2). 系统接口
kill
功能:向指定的进程或进程组发送信号
函数原型及头文件
#include
int kill(pid_t pid,int sig); 参数:
pid:目标进程的id
sig:要发送的信号编号
返回值:
成功返回0,失败返回-1
raise
功能:向自己发送信号
函数原型
#include
int raise(int sig); 参数:
sig:发送的信号编号
返回值:
成功返回0,失败返回非0值
abort
功能:向自己发送6号信号来终止程序执行。不会被signal所影响(会执行signal的自定义函数)进程还是会退出
函数原型与头文件
#include
void abort(void); 参数:无
(3). 硬件异常
#include
#include
#include
#include
void handlerSig(int sig)
{
std::cout<<"信号获取成功 ->"<
除0错误触发8号信号与野指针触发11号信号,下面分别演示
OS为什么会知道硬件异常了呢?
信号全部都是操作系统发送的。程序犯错了后被OS识别到进程犯错()再发送信号
我们要访问一个变量进程控制块task_struct一定要会经过页表映射将虚拟地址转换为物理地址后访问,在CPU的MMU(内存管理单元)负责处理CPU的内存访问请求的计算机硬件。MMU中有相应的状态信息,访问不属于我们的虚拟地址,虚拟地址转换为物理地址时就会发生错误,将错误写入到自己的状态信息中,然后操作系统就会识别到错误,进而发送信号。
(4). 软件条件
管道通信时如果读端关闭了,写端进程还一直向管道写入数据,那此时写端进程就会收到SIGPIPE信号(13号信号),因为不读了,写就没有意义。操作系统不做没有意义的事情就直接终止了。SIGPIPE就是防止进程在无意义操作中浪费资源与实践。
#include
#include
#include
#include
#include
#include
#include
#include
void handlerSig(int sig)
{
std::cout<<"信号获取成功 ->"<
&0x7f获取后七位的值
使用signal的结果如下
13号信号不解释,17号是子进程终止时系统向父进程发送的信号
通过进程等待结果如下
还能通过alarm函数来设定闹钟,到达设定时间后向我们的进程发送SIGALRM信号(14号信号)
后调用的alarm会被新的调用覆盖掉之前的定时器
函数原型与头文件
#include
unsigned int alarm(unsigned int seconds); 参数:
seconds:指定秒数后向当前进程发送SIGALRM信号,如果为0返回之前设置alarm的剩余时间。
返回值:函数返回之前定时器剩余秒数,如果之前没有设置定时器则返回0。(即之前alarm设置的秒数剩余多少秒)。
#include
#include
#include
#include
void handlerSig(int sig)
{
std::cout<<"信号获取成功 ->"<
执行结果如下所示
这篇就到这里啦,(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤