2013-10-02 27 views
4

我將有問題的代碼減少到了以下值。我有一個類C在它自己的線程上運行一個成員函數。在C的析構函數中,我想幹淨地退出這個線程。只要c是在main(1)中定義的,但是當它是全局變量(2)時,它就可以正常工作。在後一種情況下,我看到線程函數返回,但t.join()掛起。爲什麼thread.join在全局變量的析構函數中調用時失敗

#include <mutex> 
#include <condition_variable> 
#include <thread> 
#include <iostream> 

using namespace std; 

class C 
{ 
public: 
    C() 
    { 
     stop = false; 
     t = thread(&C::ThreadFunc, this); 
    } 
    ~C() 
    { 
     stop = true; 
     cv.notify_all(); 
     if (t.joinable()) 
     { 
      cout << "joining" << endl; 
      t.join(); 
      cout << "joined" << endl; 
     } 
    } 

private: 
    void ThreadFunc() 
    { 
     while (true) 
     { 
      unique_lock<mutex> lock(m); 
      cv.wait(lock, [&]{return stop;}); 
      cout << "returning" << endl; 
      return; 
     } 
    } 

    thread t; 
    mutex m; 
    condition_variable cv; 
    bool stop; 
}; 

C c; // does *not* work (2) 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    C c; // does work (1) 
    return 0; 
} 

我使用全局變量的原因是它實際上是dll的一部分。當DLL_PROCESS_DETACH上的DllMain觸發析構函數時,會發生同樣的問題。 有沒有解釋和解決這個問題?

+2

「C :: stop」必須是一個'atomic ',或者在設置它之前需要在析構函數中鎖定互斥鎖,否則就會出現數據競爭。 –

+0

@Jonathan:我嘗試過,但這不是問題的原因。 – Emile

回答

4

這是一個僵局。您正在持有一個鎖t要求終止,而您正在等待t終止。

說作爲t的分離過程的一部分,它會對DLL進行一些調用。當有一個線程(稱爲join的線程)部分連接到它時,DLL如何處理請求?一旦你開始分離,並且直到你完成分離,這個DLL是一個不一致的狀態,並且不能明智地處理線程連接和分離操作。

當你的過程處於無法控制的環境中時,你真的不想嘗試加入一個線程。

+0

這很有道理。但是,我如何處理終止?在關機時沒有加入t會導致應用程序崩潰(我認爲是因爲根據ts在運行時被破壞的文檔調用std :: terminate。 – Emile

+0

@Emile它取決於具體情況,也許你應該分離它?你可能需要獲取一個鎖定並告訴它它已被分離(取決於線程終止時你還需要做什麼) –

+0

沒有什麼可做的了,上面的例子代碼中的分離工作,但不是在真正的程序中。 R6010 - abort()在mutex.c中調用(38):mutex在忙時被破壞很明顯我需要另一種清理方式,但是我的問題是這個dll實際上是一個Lua解釋器的C擴展模塊,所以也許我可以問Lua社區,當用戶在Lua腳本中按^ Z時,是否有辦法清理。感謝您的見解。 – Emile

相關問題