转自:http://blog.sina.com.cn/s/blog_636a55070101vs2d.html转自:http://blog.csdn.net/tiany524/article/details/17048069首先感谢上述两位博主的详细讲解。虽然内容有点长,但是分析 ...
转自:http://blog.sina.com.cn/s/blog_636a55070101vs2d.html
转自:http://blog.csdn.net/tiany524/article/details/17048069
首先感谢上述两位博主的详细讲解。
虽然内容有点长,但是分析的很全面,各种实例应用基本都考虑到了。
本文将从以下几个方面来阐述信号:
(1)信号的基本知识
(2)信号生命周期与处理过程分析
(3) 基本的信号处理函数
(4) 保护临界区不被中断
(5) 信号的继承与执行
(6)实时信号中锁的研究
第一部分: 信号的基本知识
1.信号本质:
信号的本质是软件层次上对中断的一种模拟(软中断)。它是一种异步通信的处理机制,事实上,进程并不知道信号何时到来。
2.信号来源
(1)程序错误,如非法访问内存
(2)外部信号,如按下了CTRL+C
(3)通过kill或sigqueue向另外一个进程发送信号
3.信号种类
信号分为可靠信号与不可靠信号,可靠信号又称为实时信号,非可靠信号又称为非实时信号。
信号代码从1到32是不可靠信号,不可靠信号主要有以下问题:
(1)每次信号处理完之后,就会恢复成默认处理,这可能是调用者不希望看到的(早期的signal函数,linux2.6.35.6内核经验证已经不再恢复默认动作)。
(2)存在信号丢失的问题(进程收到的信号不作排队处理,相同的信号多次到来会合并为一个)。
现在的Linux对信号机制进行了改进,因此,不可靠信号主要是指信号丢失。
信号代码从SIGRTMIN到SIGRTMAX之间的信号是可靠信号。可靠信号不存在丢失,由sigqueue发送,可靠信号支持排队。
可靠信号注册机制:
内核每收到一个可靠信号都会去注册这个信号,在信号的未决信号链中分配sigqueue结构,因此,不会存在信号丢失的问题。
不可靠信号的注册机制:
而对于不可靠的信号,如果内核已经注册了这个信号,那么便不会再去注册,对于进程来说,便不会知道本次信号的发生。
可靠信号与不可靠信号与发送函数没有关系,取决于信号代码,前面的32种信号就是不可靠信号,而后面的32种信号就是可靠信号。
4.信号响应的方式
(1)采用系统默认处理SIG_DFL,执行缺省操作
(2)捕捉信号处理,即用户自定义的信号处理函数来处理
(3)忽略信号SIG_IGN ,但有两种信号不能被忽略SIGKILL,SIGSTOP
第二部分: 信号的生命周期与处理过程分析
1. 信号的生命周期
信号产生->信号注册->信号在进程中注销->信号处理函数执行完毕
(1)信号的产生是指触发信号的事件的发生
(2)信号注册
指的是在目标进程中注册,该目标进程中有未决信号的信息:
struct sigpending pending:#include}switch(act->sa_flags){case (int)SIG_DFL:printf("using default hander/n");break;case (int)SIG_IGN:printf("ignore the signal/n");break;default:printf("%0x/n",act->sa_handler);}}printf("xxxxx/n");}{int i;{while(1){}运行结果:
解释:
sigaction(i,NULL,&oldact);
signal_set(&oldact);
由于act为NULL,那么oldact保存的是当前信号的行为,当前的第二个信号的行为是执行自定义的处理程序。
当按下CTRL+C时会执行信号处理程序,输出xxxxxx,再按一下CTRL+C会停止,是由于SA_RESETHAND恢复成默认的处理模式,即终止程序。
如果没有设置SA_NODEFER,那么在处理函数执行过程中按一下CTRL+C将会被阻塞,那么程序会停在那里。
示例2: sigqueue向本进程发送数据的信号
#include}void myhandler(int signo,siginfo_t *si,void *ucontext){printf("已经收到SIGUSR1信号/n");printf("%s/n",(char*)(si->si_ptr));if(sigqueue(4403,SIGUSR1,value)==-1){//4403是目标进程pid#includevoid myhandler(int signo,siginfo_t *si,void *ucontext){ printf("the value is %d/n",si->si_int);#includeif(sigismember(&pendingmask,SIGRTMIN+10)){sigprocmask(SIG_UNBLOCK,&newmask,&oldmask);printf("SIGRTMIN+10 unblocked/n");}printf("receive signal %d/n",si->si_signo);}
程序执行:
在另一个shell发送信号:
kill -44 4579
SIGRTMIN+10 blockedsigsuspend(&sigmask);//不断的等待信号到来switch(signo){printf("received sigusr1 signal./n");printf("received sigsegv signal/n");#includeif(fork()==0){val.sival_int=10;}else {val.sival_int=20;}}void myhandler(int signo,siginfo_t *si,void *vcontext){}
输出的结果为:
子进程newact.sa_sigaction=myhandler;void myhandler(int signo,siginfo_t *si,void *vcontext){sem_wait(&sem_lock);}
此程序将一直阻塞在信号处理函数的sem_wait函数处。
2. 利用测试锁解决死锁
sem_trywait(&sem_lock);是非阻塞的sem_wait,如果加锁失败或者是超时,则返回-1。
示例2: 用sem_trywait来解决死锁
#includenewact.sa_sigaction=myhandler;void myhandler(int signo,siginfo_t *si,void *vcontext){if(sem_trywait(&sem_lock)==0){//在主线程中将信号屏蔽//主线程中对临界资源的访问sem_wait(&semlock);}void myhandler(int signo,siginfo_t *si,void *vcontext){
原标题:linux下 signal信号机制的透彻分析与各种实例讲解
关键词:linux
*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们:
admin#shaoqun.com
(#换成@)。