【发布时间】:2011-04-28 06:33:45
【问题描述】:
你能发现代码中的错误吗?门票最终低于 0 导致长时间停顿。
struct SContext {
volatile unsigned long* mutex;
volatile long* ticket;
volatile bool* done;
};
static unsigned int MyThreadFunc(SContext* ctxt) {
// -- keep going until we signal for thread to close
while(*ctxt->done == false) {
while(*ctxt->ticket) { // while we have tickets waiting
unsigned int lockedaquired = 0;
do {
if(*ctxt->mutex == 0) { // only try if someone doesn't have mutex locked
// -- if the compare and swap doesn't work then the function returns
// -- the value it expects
lockedaquired = InterlockedCompareExchange(ctxt->mutex, 1, 0);
}
} while(lockedaquired != 0); // loop while we didn't aquire lock
// -- enter critical section
// -- grab a ticket
if(*ctxt->ticket > 0);
(*ctxt->ticket)--;
// -- exit critical section
*ctxt->mutex = 0; // release lock
}
}
return 0;
}
调用函数等待线程完成
for(unsigned int loops = 0; loops < eLoopCount; ++loops) {
*ctxt.ticket = eNumThreads; // let the threads start!
// -- wait for threads to finish
while(*ctxt.ticket != 0)
;
}
done = true;
编辑:
这个问题的答案很简单,不幸的是,在我花时间精简示例以发布简化版本后,我在发布问题后立即找到了答案。叹息..
我将 lockaquired 初始化为 0。然后作为不占用总线带宽的优化,如果使用互斥体,我不执行 CAS。
不幸的是,在这种情况下,当锁被占用时,while 循环会让第二个线程通过!
很抱歉有额外的问题。我以为我不了解 Windows 低级同步原语,但实际上我只是犯了一个简单的错误。
【问题讨论】:
-
能否提供第二个代码示例的变量声明。
-
@ereOn 会的,谢谢提醒!
-
@coderdave:对你的问题表示赞同:)
-
另外一个问题是,如果你有很多线程,那些等待锁空闲的线程会随机看到下一次解锁。不幸的线程可能不得不永远等待。
-
@Bo:据我所知,他们在示例中的共享票证池上运行,所以饥饿并不重要。
标签: c++ windows multithreading synchronization