你的位置:首页 > 软件开发 > 操作系统 > linux下 signal信号机制的透彻分析与各种实例讲解

linux下 signal信号机制的透彻分析与各种实例讲解

发布时间:2016-10-12 19:00:04
转自:http://blog.sina.com.cn/s/blog_636a55070101vs2d.html转自:http://blog.csdn.net/tiany524/article/details/17048069首先感谢上述两位博主的详细讲解。虽然内容有点长,但是分析 ...

linux下 signal信号机制的透彻分析与各种实例讲解

转自: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 (#换成@)。

可能感兴趣文章

我的浏览记录