信号的介绍及使用
1.什么是信号
(1)信号是内容受限制的一种异步通信机制
(2)信号的目的是用来通信
(3)信号是异步的(对比硬件中断)
(4)信号本质上是int型数字编号(事先定义好的)
2.信号由谁发出
(1)用户在终端按下按键
(2)硬件异常后由操作系统内核发出信号
(3)用户使用kill命令向其他进程发送信号
(4)某种软件条件满足后也会发出信号,如alarm闹钟时间到会产生SIGALARM信号,向一个读端已经关闭的管道write时会产生SIGPIPE信号
3.信号由谁处理、如何处理
(1)忽略信号
(2)捕捉信号(信号绑定了一个函数)
(3)默认处理(忽略或终止进程)
4.常见的信号介绍
(1)SIGINT 2 Ctrl+c时os送给前台进程组中每个进程
(2)SIGABRT 6 调用abort函数,进程异常终止
(3)SIGPOLL SIGIO 8 指示一个异步IO事件,在高级IO中用到
(4)SIGKILL 9 杀死进程的终极方法
(5)SIGGSEGV 11 无效访问储存时OS发出该信号
(6)SIGPIPE 13 涉及管道和socket
(7)SIGALARM 14 涉及alarm函数实现
(8)SIGTERM 15 kill命令发送的OS默认终止信号
(9)SIGCHLD 17 子进程终止或停止时OS向其父进程发此信号
(10)SIGUSR1 10 用户自定义信号,作用和意义由应用者自己定义
(11)SIGUSR2 12
5.进程对信号的处理
(1)signal函数的介绍
typedef void (*sighandler_t)(int); //函数指针
sighandler_t signal(int signum, sighandler_t handler);
参数1:注册一个信号处理方法
参数2:用一个函数来处理
返回值:返回值出错时为SIG_ERR,绑定成功返回旧的捕获函数
(2)用signal函数处理SIGINT信号
(2.1)默认处理(SIG_DFL)
(2.2)忽略处理(SIG_IGN)
(2.3)捕获处理(signal函数绑定一个捕获函数后信号发生后会自动执行绑定的捕获函数,并且把信号编号作为参数传给捕获函数)
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
typedef void (*sighandler_t)(int);
//捕获函数
void func(int sig)
{
if(SIGINT != sig)
{
return;
}
printf("func for signal: %d\n",sig);
}
int main(void)
{
sighandler_t ret = (sighandler_t)-2;
//sighandler_t signal(int signum, sighandler_t handler);函数原型
//signal(SIGINT,func);
//signal(SIGINT,SIG_DFL); //让信号默认处理
ret = signal(SIGINT,SIG_IGN); //忽略处理
//ret = signal(SIGKILL,SIG_IGN);
printf("返回值为:%d\n",(int)ret);
if(SIG_ERR == ret) //判断信号处理是否成功
{
perror("signal");
exit(-1);
}
printf("before while(1)\n");
while(1);
printf("after while(1)\n");
return 0;
}
6.signal函数的缺点和优点
(1)优点:简单好用,捕获信号常用
(2)缺点:无法简单直接得知之前设置的对信号的处理方法,可移植性差(当自己设置捕获函数时就无法移植)
7.sigaction函数介绍
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
参数1:和signal一样
参数2:设置新的捕获函数
参数3:返回旧的捕获函数
(1)比signal更具有可移植性
(2)用法关键是2个sigaction指针
(3)sigaction可以一次得到(单独)设置新捕获函数和获取旧的捕获函数(要获取哪一个捕获函数设另一个为NULL)
8.alarm函数
(1)内核以API形式提供的闹钟
(2)编程实战
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void func(int sig)
{
if(sig == SIGALRM)
{
printf("alarm happend\n");
}
}
int main(void)
{
unsigned int ret = -1;
struct sigaction act = {0};
act.sa_handler = func;
//int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);函数原型
sigaction(SIGALRM,&act,NULL);
//signal(SIGALRM,func);//可以替换sigaction
ret = alarm(5);//第一次调用alarm返回值是0
printf("1st ret = %d\n",ret);
sleep(3);
ret = alarm(5);//返回值是2但是本次alarm会重新定5s
printf("2st ret = %d\n",ret);
sleep(1);
ret = alarm(5);//返回值是4依然重新定时5s
printf("3st ret = %d\n",ret);
while(1);
return 0;
}
9.pause函数
(1)内核挂起
(2)作用就是让当前进程暂停运行,交出CPU给其他进程去执行,当当前进程进入pause状态后当前进程表象为被卡住、阻塞住,要退出pause状态当前进程需要被信号唤醒。
10.使用alarm和pause来模拟sleep
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void func(int sig)
{
}
void mysleep(unsigned int sec)
{
struct sigaction act = {0};
act.sa_handler = func;
sigaction(SIGALRM,&act,NULL);
alarm(sec);
pause();
}
int main(void)
{
printf("before mysleep\n");
mysleep(3);
printf("after mysleep\n");
return 0;
}
上一篇: java设计模式之单例设计模式——-反射攻击解决方案及原理分析
下一篇: 扫二维码关注公众号