备注:我最近的项目就遇到了这个问题。只用了一个CCriticalSection对象,并且全部都有释放。但还是死活没查出死锁的原因。最后才发现原来是suspend导致的。最终用CEvent替代了suspend和resume才解决。
======================
转自:http://blog.csdn.net/magictong/article/details/4161571
今天loris分享了一个关于使用suspend造成死锁的例子,部分代码如下:
UINT AFX_CDECL ThreadTest(LPVOID pvParam) { while (TRUE) { HMODULE hHandle = ::LoadLibrary("Common.dll"); if (hHandle) { void *pFun = (void *)::GetProcAddress(hHandle, "doSomething"); ::FreeLibrary(hHandle); } ::Sleep(10); } } void CTESTWIN2Dlg::OnOK() { CWinThread *pThread = AfxBeginThread(ThreadTest, (LPVOID)this, 0, 0, CREATE_SUSPENDED); ::DuplicateHandle(::GetCurrentProcess(), pThread->m_hThread, ::GetCurrentProcess(), &m_hThread, 0, FALSE, DUPLICATE_SAME_ACCESS); pThread->ResumeThread(); m_bIsRun = TRUE; SetTimer(10, 10, NULL); } void CTESTWIN2Dlg::OnTimer(UINT nIDEvent) { if (m_bIsRun) { ::SuspendThread(m_hThread); m_bIsRun = FALSE; HMODULE hHandle = ::LoadLibrary("TSVul.dat"); if (hHandle) { void *pFun = (void *)::GetProcAddress(hHandle, "MyDoSome"); ::FreeLibrary(hHandle); } } else { ::ResumeThread(m_hThread); m_bIsRun = TRUE; } CDialog::OnTimer(nIDEvent); }
win32下的API基本都是线程安全的,因此API里面有很多线程同步的地方,LoadLibrary里面有一个临界区,线程函数在执行到LoadLibrary里面之后,如果刚好走到LoadLibrary的临界区里面,此时主线程的ontimer触发,将该线程挂起,ontimer继续执行,运行到LoadLibrary后,由于线程中LoadLibrary还没有从临界区出来,此时就造成主线程ontimer里面的LoadLibrary无限等待,主线程挂起。
因此不建议用suspend暂停线程,MSDN也有说明,suspend最好只在debug里面使用。
那怎么使线程挂起呢?可以使用事件等方式,用wait族函数来暂停线程。
【END】