早期unix信号的问题 1. 信号可能会丢失:信号发生了进程却不知道 2. 信号控制力弱: 比如有时用户希望通知内核阻塞信号(不要忽略该信号,而是在其发生时记住它,然后在进程作好了准备时再恢复之)这种 阻塞信号的能力当时并不具备。 3. 信号被抓获的时候,信号处理程序会被重置为DFL。 4. 慢性系统调用被中断时,必须手工重启之。下面的代码便是个例子: again: if ( (n = read(fd, buff, BUFFSIZE)) < 0) { if (errno == EINTR) goto again; /* just an interrupted system call */ /* handle other errors */ } 注意: 1. 中断的是系统调用,绝非函数;只有由内核执行的系统调用才会被中断 2. 慢性系统调用: 指的是可能使进程永远阻塞的系统调用. 较新的Posix.1兼容的sigaction并不使它们自动再起动。但可以使用SA_RESTART选项,使内核再起动由该信号中断的系统调用。 信号被捕捉时执行的动作 进程捕捉到信号并继续执行时,它首先执行该信号处理函数中的指令。如果从信号处理 函数 返回(例如没有调用exit或longjmp),则继续执行在捕捉到信号时进程正在执行的正常指令序列(这类似于硬件中断发生时所做的)。 信号处理程序中对于errno的处理 考虑一个信号处理 函数 ,它恰好在main刚设置errno之后被调用。如果该信号处理程序调用read,则它可能更改errno的值,从而取代了刚由main设置的值。 作为一个通用规则,当在信号处理 函数 中调用上面列出的函数时,应当在其前保存,在其后恢复errno。(要了解经常被捕捉到的信号是SIGCHLD,其信号处理 函数 通常要调用一种wait函数,而各种wait函数都能改变errno) 可靠信号原语 1. 信号递送(delivery): 执行 信号处理函数(take action) 2. 信号未决(pending) :从信号产生(generation)到信号递送之间的时间间隔 3. 信号阻塞(blocked) :信号发生时不被递送,而是暂存并于稍后递送。(SIGKILL,SIGSTOP无法被阻塞) 信号被解除阻塞 1. 当一个被设定为阻塞的信号发生多次时,当该信号被解除 阻塞 时,大多数UNIX系统采用的动作是只递送该信号一次(虽然Posix.1允许系统递送该信号一次或多次。如果递送该信号多次,则称这些信号排了队)。 2. 多个被阻塞的不同信号发生,当信号被解除 阻塞 时,Posix.1并没有规定这些信号的递送顺序。但是Posix.1建议:与进程当前状态有关的信号,例如SIGSEGV在其他信号之前递送。 |