临界区代码与信号量:wait()和signal()间临界区代码能否被中断?
关于wait()与signal()之间临界区代码是否可被中断的解答
首先直接给结论:wait()和signal()之间的临界区代码是可以被中断的,但这完全不会影响信号量实现同步/互斥的正确性——下面我拆解一下背后的逻辑:
- 先明确基础:
wait()和signal()这两个系统调用本身是原子操作,操作系统会保证它们的执行过程不会被中断服务例程打断。这是信号量机制能正常工作的核心前提,确保信号量的计数和队列操作不会出现中间状态。 - 当进程通过
wait()成功获取信号量、进入临界区后,临界区里的业务代码(也就是wait()之后、signal()之前的部分)是允许被中断的。比如:- 硬件中断(比如IO完成、定时器触发)会触发中断服务例程,当前进程会被暂停,CPU切换到处理中断;
- 如果系统是抢占式调度,更高优先级的进程就绪时,当前进程也会被抢占,让出CPU。
- 那为什么这种中断不会破坏同步?原因很简单:信号量已经被当前进程持有,其他进程调用
wait()时会因为信号量计数为0而被阻塞,根本无法进入同一个临界区。哪怕当前进程被中断暂停,共享资源依然处于被保护的状态,不会出现多个进程同时操作共享资源的竞态条件。 - 举个实际场景:假设进程A调用
wait(s)拿到了信号量,开始修改共享的全局变量。这时候来了一个磁盘IO完成的中断,CPU暂停进程A去处理中断,之后切换到进程B。进程B尝试调用wait(s),发现信号量s的计数是0,于是被挂起进入等待队列。直到进程A重新获得CPU,完成临界区操作,调用signal(s)释放信号量,进程B才会被唤醒继续执行。 - 额外补充:如果强制让临界区代码不可被中断,反而会降低系统的响应性——比如临界区里有个比较耗时的操作(比如遍历一个大数组),一直屏蔽中断的话,硬件事件会被延迟处理,可能导致系统卡顿甚至异常。所以操作系统的设计思路是:用信号量保证临界区的互斥访问,同时允许临界区代码被中断,兼顾正确性和系统性能。
内容的提问来源于stack exchange,提问作者Goktug
相关产品推荐
相关产品推荐

