信号是一种软件终端,它提供一种处理异步事件的方法,也是进程同步的唯一方法。根据POSIX标准扩展的信号机制,不仅可以通知事件,还能传递数据。
一、信号来源:
1.硬件方式
- 用户按了某些键,如ctrl+c,产生一个SIGINT信号
- 硬件异常产生信号:除数为0,无效存储访问,
2.软件方式
- kill命令
- sigqueue函数
- 某些软件发送的,如定时器
二、查看信号种类
使用明星kill -l查看系统支持的所有信号。
信号在signal.h中定义。
1.可靠信号和不可靠信号
从UNIX系统集成的1~ 31号信号为不可靠信号。POSIX.4定义的33~64之间的为可靠信号。
2.信号优先级
信号的实质是软中断,中断有优先级,所以信号也有优先级。
三、捕捉信号
1.signal
源码
#include <stdio.h>
#include <signal.h>
void handler_sight(int signo)
{
printf("recv SIGINT \n");
}
int main()
{
signal(SIGINT,handler_sight );
while(1)
{
;
}
return 0;
}
运行程序,按ctrl+c,就会触发信号。退出程序按ctrl+\
2.sigaction函数
这个函数可以用来检查或设置进程在接收到信号时的动作。
signum:函数需要操作的信号编号。可以是除SIGKILL和SIGSTOP以外的信号。
act:如果非空,则信号处理函数设置为act
oldact:如果非空,则就信号处理函数存储在oldact。
act和oldact是一个结构体sigaction。
源码如下:
#include <stdio.h>
#include <signal.h>
void handler_sight(int signo)
{
printf("recv SIGINT \n");
}
int main()
{
signal(SIGINT,handler_sight );
while(1)
{
;
}
return 0;
}
运行程序
3.pause
线程执行pause后会挂起,直到遇到信号才会唤醒。
四、信号处理函数的返回
信号处理函数可以正常返回,也可以调用其他函数返回到程序的主函数中。
实现跳转的关键字是setjmp和longjmp
使用longjmp跳转到setjmp设置的位置。
参数env是一个特殊类型jmp_buf变量。是数组的一种,存放调用longjmp时能用来恢复栈状态的所有信息。一般来说说env是一个全局变量。
示例代码:
先上一个有问题的代码。最后看运行结果和分析
运行结果:
当发送第一次信号后,程序正常处理信号。但是在发送一次的时候,信号没反应了。原因是当第一次响应信号后,信号的屏蔽字被设置。如果信号正常返回,屏蔽字是会清除的,但是信号没有正常返回,而是执行了longjmp。解决方法有两种,手动清除屏蔽字和使用sigsetjmp/siglongjmp。
sigsetjmp/siglongjmp
和setjmp相比,多了savesigs参数。如果savesigs非零,则会自动清除屏蔽字。
实例代码如下
在这里插入代码片
运行结果
信号的发送
信号发送主要由函数kill 、raise 、sigqueue、alarm、settimer、abort完成。
kill
raise
这个可以实现微妙的闹钟。
信号的屏蔽
sigsetops函数