2014-09-03 220 views
0

我試圖從類成員函數創建一個胎面,並通過類構造函數初始化程序列表初始化所述線程。線程化類成員函數;線程初始化通過初始化列表

在調用Receive_List.push_back(CurVal++)期間執行線程異常時,通過簡單地將printf()作爲函數中的第一條指令,可以避免此異常。

#include <thread> 
#include <list> 


class SomeClass 
{ 
    std::thread Receive_Thread; 
    std::list<unsigned int> Receive_List; 

    void Receive_Main() 
    { 
     //printf("Hacky Way Of Avoiding The Exception\n"); 
     const unsigned int MaxVal = 3000; 
     unsigned int CurVal = 0; 
     while (CurVal < MaxVal) 
     { 
      Receive_List.push_back(CurVal++); 
     } 
    } 

public: 
    SomeClass() : 
     Receive_Thread(std::thread(&SomeClass::Receive_Main, this)) 
    {} 

    ~SomeClass() 
    { 
     Receive_Thread.join(); 
    } 

    void ProcessReceiveList() 
    { 
     if (!Receive_List.empty()) 
     { 
      printf("Received Val: %i\n", Receive_List.front()); 
      Receive_List.pop_front(); 
     } 
    } 

    bool IsReceiveEmpty() 
    { 
     return Receive_List.empty(); 
    } 
}; 


int main() 
{ 
    SomeClass* MyObject = new SomeClass(); 

    // 
    // Sleep for 1 second to let the thread start populating the list 
    std::this_thread::sleep_for(std::chrono::seconds(1)); 

    while (!MyObject->IsReceiveEmpty()) 
    { 
     MyObject->ProcessReceiveList(); 
    } 

    delete MyObject; 
    std::system("PAUSE"); 
    return 0; 
} 

這是怎麼發生的?

回答

2

您正在觀察的問題是由列表初始化之前啓動的線程引起的,給出數據競賽,這會導致未定義的行爲。添加printf會延遲第一次訪問列表,以便初始化更可能在訪問之前完成。這不是而是雖然修正了數據競爭;它可以通過固定前聲明列表螺紋:

std::list<unsigned int> Receive_List; 
std::thread Receive_Thread;// WARNING: must be initialised last 

你有進一步的問題:所有訪問至由一個線程修改和更新由另一個必須同步數據;通常通過守衛它mutex。如果沒有同步,您又會遇到數據競爭,導致未定義的行爲。

所以互斥添加到類守衛名單:

#include <mutex> 

class SomeClass { 
    std::mutex mutex; 
    //... 
}; 

並鎖定它,當你訪問列表

while (CurVal < MaxVal) 
{ 
    std::lock_guard<std::mutex> lock(mutex); 
    Receive_List.push_back(CurVal++); 
} 

,同樣在訪問列表中的其他功能。

+0

這對我來說沒有意義,爲什麼取消註釋'printf()'允許代碼無例外地執行。我的印象是,簡單地使用list :: push和list :: pop函數可以同時運行,沒有問題。另外,將主線程中的while循環替換爲'while(true){}'仍然會導致異常。 – KKlouzal 2014-09-03 10:40:57

+0

@KKlouzal:未定義的行爲往往沒有意義。不,標準容器不同步;你需要自己照顧自己。確實還有另外一個問題,我會在答案中加入。 – 2014-09-03 10:47:07

+0

非常感謝您提供的所有信息。我不知道在類定義中聲明變量的順序表示它們被初始化的順序。 – KKlouzal 2014-09-03 10:51:38