为何BACI监视器函数无法共享变量/条件?并发程序死锁排查
并发程序死锁问题排查(基于Ben-Ari Concurrent Interpreter)
我正在编写一个并发程序,要求按顺序打印字母A和B。以下程序语法正确且可编译,但每次运行都会发生死锁:
monitor simple_monitor { int isAPrinted = 0; condition B_wait; void monitorA() { isAPrinted = 1; cout << "A: Value of isAPrinted is now " << isAPrinted << endl; signalc (B_wait); } void monitorB() { cout << "B: Value of isAPrinted is now " << isAPrinted << endl; if ( !isAPrinted ) waitc( B_wait ); } } int main() { cobegin { monitorA(); monitorB(); } }
具体错误输出如下:
Executing PCODE ... A: Value of isAPrinted is now 1 B: Value of isAPrinted is now 0 BACI System: Command-line PCODE Interpreter in Java, 09:46 05 Nov 2007 Execution of process 2 aborted at loc 23 >>>Deadlock in process 2 Process Active Suspend PC xpc atomic 0 main 0 6000 38 0 0 1 monitorA 0 -1 0 0 0 2 monitorB 0 2607 23 0 0 ...
当monitorB先运行时,本应等待B_wait,待monitorA执行signalc(B_wait)后唤醒,但实际未被唤醒;当monitorA先运行时,本应将isAPrinted设为1,使monitorB无需等待,但monitorB运行时isAPrinted仍为0,仿佛两个函数处于独立的执行上下文。我使用的是javabaci(Ben-Ari Concurrent Interpreter,一款大学操作系统课程教学用的并发解释器),类似示例程序可正常运行,请问问题出在哪里?
问题根源
你在cobegin中直接调用监视器成员函数monitorA()和monitorB(),但Ben-Ari的监视器语法要求必须通过监视器对象调用成员函数。当前写法下,两个函数并未进入监视器的临界区,共享变量isAPrinted不受互斥机制保护,导致数据不一致、信号操作无效,最终引发死锁。
修复方案
- 实例化监视器对象;
- 通过对象调用成员函数;
- 将
monitorB中的if条件判断改为while——这是监视器编程的标准实践,可避免虚假唤醒导致的逻辑错误。
修复后的代码:
monitor simple_monitor { int isAPrinted = 0; condition B_wait; void monitorA() { isAPrinted = 1; cout << "A: Value of isAPrinted is now " << isAPrinted << endl; signalc (B_wait); } void monitorB() { cout << "B: Value of isAPrinted is now " << isAPrinted << endl; // 用while循环检查条件,处理虚假唤醒 while ( !isAPrinted ) waitc( B_wait ); } } int main() { // 实例化监视器对象 simple_monitor m; // 通过对象调用成员函数,确保进入监视器临界区 cobegin { m.monitorA(); m.monitorB(); } }
修复说明
- 实例化监视器对象后,所有成员函数调用都会进入互斥临界区,保证
isAPrinted的读写操作原子性; signalc和waitc会正确关联到该对象的条件变量B_wait,唤醒等待的进程;while循环替代if,可避免进程被意外唤醒时跳过条件检查,确保逻辑正确性。
内容的提问来源于stack exchange,提问作者Mark Peschel
相关产品推荐
相关产品推荐

