linux中的信号
什么是信号
信号的目的:用来通信
信号是异步的(对比硬件中断)
信号本质上是int型数字编号(事先定义好的)
信号由谁发出
用户在终端按下按键
硬件异常后由OS内核发送信号
用户使用kill命令向其他进程发送信号
某种软件条件满足后也会发送信号,如alarm闹钟时间到会产生SIGALARM信号,向一个读端已经关闭的管道write时会产生SIGPIPE信号
信号由谁处理、如何处理
三种处理方式
忽略信号
捕获信号(进程的信号执行函数)
默认处理(进程没有明显的管理这个信号,默认:忽略或者终止进程)
常见信号介绍
在/usr/include/x86_64-linux-gnu/bits$ 里的signum.h文件里面
编号
SIGINT 2 Ctril+C时OS给前台进程组中每个进程
SIGABRT 6 调用abort函数,进程异常终止
SIGPOLL SIGIO 8 指示一个异步IO事件,在高级IO中
SIGKILL 9 杀死进程的终极方法
SIGSEGV 11 无效存储访问时OS发出该信号(数组越界返回的警告信息)
SIGPIPE 13 涉及异步通信的管道和socket
SIGALARM 14 设计alarm函数(闹钟功能)的实现
SIGTERM 15 kill命令发送的OS默认终止信号
SIGCHLD 17 子进程终止或停止时OS向其父进程发送此信号
SIGUSR1 10 用户自定义信号,作用与意义自己定义
SIGUSR2 12
进程对信号的处理
signal函数
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>void func(int sig)
{
if(SIGINT != sig)
return;
printf("\nfunc for signal: %d.\n",sig);
}int main(void)
{
signal(SIGINT, func);//收到SIGINT信号后会执行这个函数。return 0;
}
用signal函数处理SIGINT信号
默认处理
忽略处理
捕获处理
signal函数绑定一个捕获函数后,信号发生后会自动执行绑定捕获函数,并将信号编号作为传参传给捕获函数
signal函数的返回值在出错时为SIG_ERR;绑定成功时返回旧的捕获函数
signal函数的有点和缺点
优点:简单好用,捕获信号常用
缺点:无法简单直接得知之前设置的对信号的处理方式
sigaction函数
与signal函数相比具有较好的可移植性。
用法关键:两个sigaction指针
sigaction可以一次得到设置新捕获函数和获取旧的捕获函数(其实还可以单独设置新的捕获或者单独只获取旧的捕获函数)
alarm和pause函数
alarm函数
内核以API形式提供的闹钟
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void func(int sig)
{
if(SIGALRM == sig)
{
printf("alarm happened.\n");
}
}
int main()
{
unsigned int ret = -1;
struct sigaction act = {0};
act.sa_handler = func;
//signal(SIGALRM, func);
sigaction(SIGALRM, &act, NULL);
ret = alarm(3);
while(1);
printf("ret = %d.\n", ret);
return 0;
}
pause函数
内核挂起
作用:进程暂停运行,交出CPU给其他进程执行,当当前进程进入pause状态后当前进程就会表现为“阻塞”,退出pause状态当前进程需要被信号唤醒。
使用alarm和pause来模拟sleep
void mysleep(unsigned int sec)
{
struct sigaction act = {0};
act.sa_handler = func;
sigaction(SIGALRM, &act, NULL);
alarm(sec);
}