SIGSTOP和SIGKILL区别是:前者是使进程暂时停止,即中止,也就是说使进程暂停,将进程挂起,比如你在终端里面执行一个脚本或者程序,执行到一半,你想暂停一下,你按下ctrl+z,就会导致终端发送一个SIGSTOP信号给进程,然后程序会暂停,然后我们再用kill命令给进程发送一个第18号信号SIGCONT,内核会安排进程继续执行,如下图所示。
Linux上的信号列表
APUE上SIGCLD语义写的有点不清楚,到底我们的系统是如何来处理SIGCLD信号呢?
1.SIG_DFL :默认的处理方式是不理会这个信号,但是也不会丢弃子进行状态,所以如果不用wait,waitpid 对其子进行进行状态信息回收,会产生僵尸进程。
2.SIG_IGN :忽略的处理方式,这个方式和默认的忽略是不一样的语意,暂且我们把忽略定义为SIG_IGN,在这种方式下,子进程状态信息会被丢弃,也就是自动回收了,所以不会产生僵尸进程,但是问题也就来了,wait,waitpid却无法捕捉到子进程状态信息了,如果你随后调用了wait,那么会阻塞到所有的子进程结束,并返回错误ECHILD,也就是没有子进程等待。
3.自定义处理方式:SIGCLD会立即检查是否有子进程准好被等待,这便是SIGCLD最大漏洞了,一旦在信号处理函数中加入了信号处理方式重建的步骤,那么每次设置SIGCLD处理方式时,都会去检查是否有信号到来,如果此时信号的确到来了,先是调用自定义信号处理函数,然后是调用信号处理方式重建函数,在重建配置的时候,会去检查信号是否到来,此时信号未被处理,会再次触发自定义信号处理函数,一直循环。所以在处理SIGCLD时,应该先wait处理掉了信号信息后,再进行信号处理方式重建signal。
解决方式:在信号处理函数中,先wait()子进程,在进行signal()信号设置。
但这与在10.4中提到的不可靠信号的应对方式相矛盾:在被调用的信号捕捉函数中,首先配置信号处理。
可靠信号:
在UNIX系统中,能产生信号的事情有很多,比如你的程序中做了除以0的运算,比如你设置的alarm定时器时间到了,比如你在终端正在执行一个脚本,执行到一半,你想取消,按下ctrl+c,然后终端就产生一个信号,诸如此类都可以导致产生一个信号。
上面是产生信号,产生信号后,内核要将发生了某某信号告诉相应的程序,内核通过在进程的进程表(PCB)中设置一个标志,以表示信号递交(递送,delivery),在产生和递交之间的时间窗口期间,称信号的状态是未决的(pending)。