信号的概念
信号在我们的生活中随处可见,如:古代战争中摔杯为号;现在战争中的信号弹;体育比赛中使用的信号枪。。。
他们都有共性: 1.简单 2.不能携带大量的信息 3.满足某个特设条件才发送。
信号是信息的载体,Linux/Unix 环境下,古老 、经典的通信方式,现在依然是主要的通信手段.
Unix早期版本就提供了信号机制,但不可靠,信号可能丢失。Berkeley和AT&T都对信号模型做了修改,增加了可靠信号机制。但彼此不兼容。POSIX.1对可靠信号例程进行了标准化.
信号的机制
A给B发生信号,B收到信号之前执行自己的代码,收到信号后,不管执行到程序的什么位置,都有暂停运行,去处理信号,处理完毕再进行执行。与硬件中断类似--异步模式。但信号是软件层面上实现的中断,早期常被称“软中断”
信号的特质 由于信号是通过软件方法实现,其实现手段导致信号有很强的延时性。但对于用户来说这个延时非常短,不易察觉.
每个进程收到的所有信号,都是有内核负责发送的,内核处理.
与信号相关的事件和状态
产生信号
1.按键产生 如 Ctrl+c Ctrl+z Ctrl=\
2.系统调用 如 kill raise abort
3.软件条件产生 如 alarm
4.硬件异常 如:非法访问内存(段错误),除0,内存对齐出错
5.命令产生 如:kill命令
递达:递达并且到达进程
未决信号集
阻塞信号集(信号屏蔽字 set)
9号和19信号不允许忽略和捕捉,只能执行默认动作。
alarm函数
设置定时器,在指定seconds后,内核会给当前继承发送14信号。进程收到该信号,默认动作终止。
每个进程有且只有一个定时器 常用:取消定时器 alarm(0),返回旧闹钟剩余秒数。
定时与进程状态无关!就绪 运行 挂起 终止 僵尸 无论进程处于何种状态,alarm都计时
信号捕捉特性
进程正常运行时,默认PCB中有一个信号屏蔽字,他决定了进程自动屏蔽哪些信号。当注册了某个信号的捕捉函数,捕捉到该信号后,要调用该函数。而该函数有可能执行很长时间,在这期间所屏蔽的信号有sa_mask来指定。
XXX信号捕捉函数执行期间,XXX信号自动被屏蔽
阻塞的常规信号不支持排队,产生多次只记录一次。(后32个实时信号支持排队)
解决时序问题
可以通过设置屏蔽SIGGALRM的方法来控制程序执行逻辑,但无论如何设置,程序都有可能在“解除信号屏蔽”和“挂起等待信号”这两个操作间隙失去CPU。除非将这两个步骤合并成一个原子操作。sigsuspend函数具备这个功能。在对时序要求严格的场合下都应该使用sigsuspend替换pause.
sigsuspend函数调用期间,进程信号屏蔽字有其参数mask指定。
可以将每个信号从临时信号屏蔽字mask中删除,这样在调用sigsuspend时将解除对该信号的屏蔽,然后挂起,当sigsuspend返回时,进程的信号屏蔽字恢复原来的值。如果原来对该信号是屏蔽,sigsuspend函数返回后仍然屏蔽该信号
竞态条件,跟系统负载有很紧密的关系,体现出信号的不可靠。系统负载越严重,信号不可靠性越强。
不可靠由其实现原理所致。信号是通过软件方式实现,每次系统调用结束后或中断处理结束后,需要通过扫描PCB中的未决信号集,来判断是否应处理某个信号。当系统负载过重时,会出现时序混乱。
这种意外情况只能在编程中,提早预见,主动规避,而无法通过gdb程序调试等其他手段弥补。且由于其不具规律性,后期捕捉和重现十分困难。