【发布时间】:2011-02-14 14:26:34
【问题描述】:
我有一个程序会生成 3 个工作线程,它们会进行一些数字运算,并等待它们完成,如下所示:
#define THREAD_COUNT 3
volatile LONG waitCount;
HANDLE pSemaphore;
int main(int argc, char **argv)
{
// ...
HANDLE threads[THREAD_COUNT];
pSemaphore = CreateSemaphore(NULL, THREAD_COUNT, THREAD_COUNT, NULL);
waitCount = 0;
for (int j=0; j<THREAD_COUNT; ++j)
{
threads[j] = CreateThread(NULL, 0, Iteration, p+j, 0, NULL);
}
WaitForMultipleObjects(THREAD_COUNT, threads, TRUE, INFINITE);
// ...
}
工作线程在代码中的某些点使用自定义的 Barrier 函数等待所有其他线程到达 Barrier:
void Barrier(volatile LONG* counter, HANDLE semaphore, int thread_count = THREAD_COUNT)
{
LONG wait_count = InterlockedIncrement(counter);
if ( wait_count == thread_count )
{
*counter = 0;
ReleaseSemaphore(semaphore, thread_count - 1, NULL);
}
else
{
WaitForSingleObject(semaphore, INFINITE);
}
}
(基于this answer实现)
程序偶尔会死锁。如果那时我使用 VS2008 来中断执行并在内部进行挖掘,那么在 Barrier() 的 Wait... 行上只有 1 个工作线程在等待。 waitCount 的值始终为 2。
为了让事情更尴尬,线程工作得越快,它们就越有可能死锁。如果我在 Release 模式下运行,死锁会出现 10 次中的 8 次。如果我在调试模式下运行并在线程函数中放置一些打印以查看它们挂起的位置,它们几乎不会挂起。
所以看来我的一些工作线程被提前杀死了,剩下的就卡在了 Barrier 上。但是,线程实际上除了读写内存(并调用Barrier())之外什么都不做,而且我非常肯定不会发生段错误。我也有可能得出错误的结论,因为(如上面链接的问题中所述)我是 Win32 线程的新手。
这里可能发生了什么,我如何使用 VS 调试这种奇怪的行为?
【问题讨论】:
-
如果一个线程正在死亡,您至少应该看到附带的调试器出现第一次机会异常的证据。另外,当您在挂起期间进行调试中断时,其他两个工作线程在做什么?
-
我刚去Debug -> Exceptions...,检查了每一个异常类型,但是死锁没有中断就发生了。这是否意味着我的线程“正常”停止并且我的设计有缺陷?此外,当我在挂起期间中断时,其他两个工作线程根本不会显示在“线程”窗口中:只有主线程和一个工作线程。
-
好的,听起来你已经涵盖了你的异常,用于调试。其他后台线程是否有可能只是正常终止?输出窗口将显示类似“线程## 已退出,代码为 0”。
-
你说的很对,输出窗口(我一直忘记它存在......)说两个线程以代码0退出。我想我应该重新评估
Barrier()的正确性? -
停止编写自己的同步原语,开始使用系统提供的优秀同步原语。
标签: c++ multithreading visual-c++