2015-06-23 37 views
5

關於std::thread有一點我不明白: 爲什麼std::thread的構造函數需要函數運行rvalue?爲什麼std :: thread函數是由右值運行的?

我通常想與一些成員運行Functor到另一個線程。像這樣:

struct Function 
{ 
    void operator() (/* some args */) 
    { 
     /* some code */ 
    } 

    /* some members */ 
} 


void run_thread() 
{ 
    Functor f(/* some data */); 
    std::thread thread(f, /* some data */); 

    /* do something and wait for thread to finish */ 
} 

當前實現std::thread我必須確定我的對象是實現移動語義。我不明白爲什麼我不能通過引用來通過它。

額外的問題是:什麼意思是通過右值引用函數? Lambda表達式?

+4

'std :: thread'的構造函數通過轉發引用來實現其功能。 –

+0

你的對象不需要實現移動語義。如果移動不被支持,它只需要複製。 – nwp

+0

@nwp:什麼情況下,什麼時候該對象已經刪除了複製構造函數?爲什麼需要該副本? –

回答

6

在你的run_thread方法中,f是一個自動變量。這意味着f範圍的底部將被銷燬。你聲稱你將「等待線程完成」,但編譯器/運行時系統不知道!它必須假定f將被刪除,可能在應該調用其方法的線程有機會開始之前。

通過複製(或移動)f,運行時系統獲得對其副本f的生命週期的控制權,並且可以避免一些非常令人討厭且難以調試的問題。

3

std::reference_wrapper將公開operator()到包裝的對象。如果您願意進行手動終身維護,std::thread t(std::ref(f));將通過引用運行f

當然,在您的代碼中,這會導致未定義的行爲,因爲您沒有正確管理生命週期。


最後,請注意生thread是一個糟糕的「客戶端代碼」工具。 async是一個更好的觸摸,但是真的需要一個帶有packaged_task s和future s和條件變量的任務隊列。 C++ 11增加了足夠的線程支持來編寫體面的線程系統,但它提供了原語,而不是「客戶端代碼」工具。

在玩具程序中,它可能已經足夠。

相關問題