2017-08-28 72 views
2

我希望等待使用條件變量。多等待使用通知全部

我已經創建了一個包含10個線程的程序,每個線程都在主線程中等待信號notify_all()。但它陷入僵局,我不想理解爲什麼。

#include <iostream>   // std::cout 
#include <thread>    // std::thread 
#include <mutex>    // std::mutex, std::unique_lock 
#include <condition_variable> // std::condition_variable 
#include <chrono> 

using namespace std; 

std::mutex mtx; 
std::condition_variable cv; 
int xx = 0; 

void print_id (int id) { 
    std::unique_lock<std::mutex> lck(mtx); 
    cout<<"Start thread id " << id << " \n"; 

    for(int i=0; i<9; i++) 
    { 
     cout<<"Thread " << id << " i " << i <<"\n"; 
     cv.wait(lck); 
    } 
} 

void go() 
{ 
    cv.notify_all(); 
    for(int i=0; i<10; i++) 
    { 
     //Some works for threads 
     cv.notify_all(); 
    } 
} 

int main() 
{ 
    std::thread threads[10]; 
    for (int i=0; i<10; ++i) 
     threads[i] = std::thread(print_id,i); 

    std::cout << "10 threads ready to race...\n"; 
    go();      // go! 

    for (auto& th : threads) th.join(); 
} 
+2

除非您有什麼需要等待的地方,否則不能調用wait。你不能調用'notify_all',除非你有通知的線程。而且,最糟糕的是,你的互斥鎖並不能保護任何東西!它應該是保護你正在等待的東西以及你正在通知的東西! –

回答

3

這不是條件變量的工作方式。

要認識到的主要問題是條件變量不能可靠地單獨發出事件信號。特別是,wait()調用可能會虛假地返回,也就是說,沒有任何人調用notify

相反,你需要的是邏輯條件在你的周邊程序中,條件變量是綁定的。只要條件發生變化,您就會通知通知,並且wait檢查條件,either as part of a surrounding loop or inside the wait by providing a checker predicate function as an argument to the call

另一個問題需要注意的是,雖然等待不能繼續沒有通知存在的(在邏輯上,假設沒有雜散喚醒),相反的是不正確的。也就是說,即使在print_id函數已經達到第一次等待之前,go()函數也可能會運行完成。那樣的等待將永遠被阻止,因爲在途中沒有更多的通知。通知不會等待等待,它們是「即燃即用」操作。

在正確使用的條件變量,這不是一個問題,因爲等待只是等待的邏輯條件改變。如果在等待呼叫之前已經發生了這種變化,那麼您會發現它,並且不要在第一時間呼叫等待。

什麼你可能想在這裏是一個barrier的行爲。您可以使用int計數器的條件和condition_variable和同步mutex輕鬆地實現自己的屏障。

+0

回覆,「通知已不等待等待......」的另一種說法是,'cv.notify()'和'cv.notify_all()'在ALL_不做_anything除非有其他線程已經在等待一個'cv.wait()'調用。 –