2013-06-19 43 views
8

我不明白爲什麼這個簡單的代碼段有一個死鎖:的std ::的Thread.join()的僵局

#include <atomic> 
#include <thread> 
#include <memory> 

using namespace std; 
class Test { 
public: 

    Test() : mExit(false) 
    { 
     mThread = thread(bind(&Test::func, this)); 
    } 

    ~Test() 
    { 
     if (mThread.joinable()) 
     { 
      mExit = true; 
      mThread.join(); 
     } 
    } 

private: 
    void func() 
    { 
     while (!mExit) 
     { 
      // do something 
     } 
    } 

private: 
    atomic<bool> mExit; 
    thread mThread; 
}; 

typedef unique_ptr<Test> TestPtr; 
TestPtr gTest; 

int main() 
{ 
    gTest = TestPtr(new Test); 
    return 0; 
} 

編輯 我打字錯誤的contstructor設置MEXIT =真

編輯2 我正在使用msvc2012和v110_xp工具集。

編輯3 問題消失,如果我明確地內主要

+3

'mExit = false' ?? –

+0

我輸錯了,抱歉。問題依然存在。 –

+0

嗯。在你正確使用原子之前,這可能不會變好。並使用調試器來找出線程正在做什麼。在雜草中關閉的可能性相當大,阻止了一些操作系統調用,而不是一次又一次地燃燒100%核心檢查退出條件。 –

回答

6

我剛剛遇到了這個問題,所以我發佈了其他人的真實答案。

在Visual Studio中,至少有一個「退出鎖定」,當線程進入退出代碼時(即主線程爲main()之後,以及在std::thread(f)之後爲f()),該鎖定被鎖定。

由於您的測試類只在main()完成後被破壞,所以「退出鎖定」被鎖定。只有您設置了mExit = true;並且允許其他線程完成。然後這個其他線程等待獲得主線程已經佔用的「退出鎖定」,而主線程在mThread.join();中等待,導致死鎖。

所以是的,你需要在主線程完成之前加入你所有的線程。

3

調用gTest.release()給我的代碼看起來不錯,如果它的好與當地DUT壞全球我懷疑類相關deinit序列。連接在退出時發生很深,實現可能已經消除了一些結構。它不應該是這樣,但可能。

在任何情況下,我總是避免在main之前啓動線程,並留下main的任何延伸結束。我認爲只是要求麻煩。如果你可以重新安排它來強制連接,那麼整個問題可能會消失。

另外你應該使用原子上的atomic_flag。

+0

使用atomic_flag原子或atomic_bool我有一些好處嗎?我必須研究更好的原子。 –

+0

atomic_flag是一個確定的原子事物,最基本的元素。其他類型允許使用內部互斥實現。國際海事組織不太可能,但爲什麼要冒險 –

+0

@BalogPal因爲'atomic_flag'是使用的皇家痛苦嗎? ;) – ComicSansMS

0

將代碼從

gTest = TestPtr(new Test);

auto gTest = std :: make_unique();

消除了這個問題。

上面的問題與全局對象一樣。