2016-05-07 73 views
3

我有以下的代碼塊,我的預期是拉姆達捕獲列表內的i是按值傳遞和i輸出應該是不同的。爲什麼這個lambda函數在循環中沒有按值捕獲參數?

然而,實際的結果是輸出20行19 is completed

我試圖將這一行std::thread t([&func](){改爲std::thread t([func](){,輸出結果可能會打印出不同的i值。

我的問題是爲什麼std::thread t([&func](){std::thread t([func](){會導致我不同的輸出值?

void DoSomething(std::function<void()> func) 
{ 
    std::thread t([&func](){ 
     //do something 
     sleep(1); 
     if (func) 
      func(); 
    }); 
    t.detach(); 
} 

int main(int argc, const char * argv[]) { 
    std::mutex mtx; 
    for (int i = 1 ; i < 20; i ++) { 
     DoSomething([i, &mtx](){ 
      std::unique_lock<std::mutex> lock(mtx); 
      std::cout << i << " is completed" << std::endl;; 
     }); 
    } 
    sleep(10); 
} 

回答

2

你捕捉到DoSomething的參數,func參考。
當你的線程執行的時候,這個參數的生命週期已經結束了,所以你有一個懸而未決的引用,並且使用它是未定義的。

+0

是指傳遞到的DoSomething的FUNC攜帶捕獲列表中的信息? – 2power10

+0

@ 2power10我不確定你在問什麼。如果您通過引用捕獲,則需要確保引用的對象在使用時有效,否則程序未定義。以價值捕獲是在這裏要做的正確事情。 – molbdnilo

0

線程對象t in DoSomething()接收對按值傳遞的func對象的引用。當執行func()時,它可能正在通過調用std::unique_lock<std::mutex> lock(mtx);等待mutex在此期間t.detach()將被調用,並且該函數將通過銷燬值參數func而退出。這將導致@molbidnilo所說的懸而未決的引用。

的問題可以通過調用t.join();代替t.detach()來解決。

+0

使用't.join()'會阻止'DoSomething',這就是爲什麼我在這裏使用't.detach()'的原因。我認爲這個問題可以通過取值而不是引用來解決。 – 2power10

0

如果使用t.detach(),線程獨立運行,現在你通過引用傳遞函數對象,因此,如果函數對象被破壞時的獨立線程試圖指,那不是導致死機的程序。 但是如果你通過值傳遞函數對象,這個問題就解決了。我在我的機器上測試了你的代碼,當通過引用使用傳遞的函數對象時,它崩潰了。

相關問題