产生原因:仍然以前文实现的sleep函数为例,如果进程在执行完alarm函数后,突然失去CPU,被阻塞等待(这是有可能的,进程在执行过程中,若非原子操作,都有可能随时失去CPU),如果失去CPU的时间大于了sleep函数需要睡眠的时间,则此时在执行pause函数前,信号已经到了,因此会先处理信号(软中断,而不是先执行pause函数),在信号处理完后,再去执行pause函数,此时进程会被永远挂起,不会被唤醒,因为SIGALRM信号已经被处理了。时序竞态:即由于进程之间执行的顺序不同,导致同一个进程多次运行后产生了不同结果的现象。如上述sleep函数,有时执行结果是正确的,有时却会导致进程永远被挂起,因此这就是一个时序竞态问题。因此需要重新对该函数进行改进。
1. 注册SIGALRM信号处理函数(sigaction...)
2. 调用alarm(1) 函数设定闹钟1秒。
3. 函数调用刚结束,开始倒计时1秒。当前进程失去cpu,内核调度优先级高的进程(有多个)取代当前进程。当前进程无法获得cpu,进入就绪态等待cpu。
4. 1秒后,闹钟超时,内核向当前进程发送SIGALRM信号(自然定时法,与进程状态无关),高优先级进程尚未执行完,当前进程仍处于就绪态,信号无法处理(未决)
5. 优先级高的进程执行完,当前进程获得cpu资源,内核调度回当前进程执行。SIGALRM信号递达,信号设置捕捉,执行处理函数sig_alarm。
6. 信号处理函数执行结束,返回当前进程主控流程,pause()被调用挂起等待。(欲等待alarm函数发送的SIGALRM信号将自己唤醒)
7. SIGALRM信号已经处理完毕,pause不会等到。