今天我读完了APUE(第3版)一书的第10章信号,在做习题10.6的时候遇到了问题。这道题是要求用本章基于信号实现的tell/wait函数,实现父进程与子进程之间的同步,依次把一个数字加1。
出于偷懒的目的,我从APUE一书的官网下载了配套的源代码,这样我就不用把tell/wait函数敲进去了。我发现在下载的源代码的lib路径下有个tellwait.c。放在这里想必是作者对这个代码很有信心吧,将其作为了库函数。经比对,与书中的代码一致。
程序写好后,编译运行,程序跑了几下就停在那里了。我反复检查代码,感觉我写的没有问题。把代码提交给Gemini后,它发现代码存在如下问题。
1. tellwait.c中用signal()函数注册信号处理程序,正如这一章开头作者大讲的不可靠信号的问题。可是不知道为什么作者后面写的代码又用了不可靠的信号。
用signal()注册的SIGUSR1和SIGUSR2信号处理程序,在执行一次之后需要重复注册,否则系统对于这个信号就采用默认处理方式了,也就是结束进程。我写的程序,子进程在处理了一次信号后,又一次收到信号,就直接退出了,所以永远不会TELL_PARENT(), 父进程也就永远停在了那里。
要解决这个问题,需要把signal()函数替换为sigaction().
2. WAIT_PARENT()和WAIT_CHILD()中,sigsuspend()返回后,调用sigprocmask()恢复了原来的信号屏蔽。所以如果再一次调用这两个函数,那就出现了书中讲的竞争问题及不可靠信号。
如果要反复调用这两个函数的话,就得把这两个WAIT_xxx函数对sigprocmask()的调用取消,这样SIGUSR1和SIGUSR2在整个程序运行中一直是屏蔽状态,只有sigsuspend()的时候才能接收SIGUSR1和SIGUSR2并处理。
综上,我认为作者在信号这一章比较靠后的位置,已经讲了信号的大部分知识后,写的这个tellwait.c是不严谨的。这些函数,只有第一次调用才好用,如果反复调用就会出问题,需要按我上面说的进行修改。








