2015-11-04 65 views
0

我有一個相當簡單的需求,但我對使用std :: thread並不確定我理解它是否正確。在std :: thread中等待條件A或條件B

我的線程的任務是運行一個循環:等到對象需要處理,處理它,然後等待,...

我正要實施這一使用condition_variable我才意識到,雖然螺紋正坐着等待一個新的對象,它不會注意到已經設置了一個stopThread標誌。

我實際上想要一個辦法做wait_for_either(new_data,exit_thread)但我不確定如何優雅地實現這一點。類似隊列函數的舊代碼使用Windows API WaitForMultipleObjects,但我想用它作爲學習C++ 11方法的機會。

回答

0

半僞代碼。

std::atomic_bool programRunning; 
std::condition_variable cv; 
std::mutex mtx; 

std::thread loopThread([&]{ 
    while(programRunning.load()){ 
     std::unique_lock<std::mutex> lock(mtx); 
     if (newDataAvailable){ 
      //process new data 
     } else{ 
      cv.wait(lock,[&]{ return dataAvailable || !progamRunning.load(); }); 
     } 
    } 

}); 

{ 
    std::lock_guard<std::mutex> lock(mtx); 
    queueMoreData(); 
    cv.notify_one(); 
} 

//on exit: 
programRunning.store(false); 
cv.notify_one(); 
+0

我知道你在使用lambdas,但是'[&] {...}'語法是什麼? –

+0

通過引用抓住一切,沒有參數 –

+0

我會做一個永久循環,等待,並打破自己。另外,你應該讓你的'newDataAvailable'具有相同的名字。 ;)接下來,您可能不希望在整個處理數據期間持有互斥鎖;這使得排隊等待新數據的人們必須等待舊數據的處理。 – Yakk

4

當您等待數據處理時,您實際上正在等待條件變量發出信號。所以,當你想要退出線程時,只需要指示條件變量,就好像stopThread標誌是一個特殊的數據來處理。

的代碼可能看起來像:

void thread_func() 
{ 
    std::unique_lock<std::mutex> lock(mutex); 
    for (;;) 
    { 
     cond.wait(lock, []() { return stopThread || !dataContainer.empty(); }); 
     if (stopThread) 
      return; //exit thread 
     //process data from dataContainer 
    } 
} 

要插入數據:

{ 
    std::unique_lock<std::mutex> lock(mutex); 
    dataContainer.push_back(new_data); 
    cond.notify_all(); 
} 

然後,當你想停止線程:

{ 
    std::unique_lock<std::mutex> lock(mutex); 
    stopThread = true; 
    cond.notify_all(); 
} 
thread.join(); //not necessary but probably a good idea 
+1

我想你的意思是使用'wait'而不是'wait_for'。 'wait_for'需要指定的時間。 – NathanOliver

+0

這將使用'condition_var_any',對吧?我假設條件函數是簡單地週期性地調用的 - 這個函數是否需要線程安全或是有保證的? –

+0

@NathanOliver:是的,當然會糾正。 – rodrigo

1

這是一個強大的數據消耗迴路中止選項:

while(true) { 
    decltype(dataContainer) data; 
    { 
    std::unique_lock<std::mutex> lock(mutex); 
    cond.wait(lock, []() { return stopThread || !dataContainer.empty(); }); 
    if (stopThread) 
     return; //exit thread 
    data = std::move(dataContainer); 
    } 
    for (auto&& d:data) { 
    if (stopThread) return; // abort 
    //process data from d 
    } 
} 

stopThreadatomic或在底部需要有mutex加以防護在for(:)環路接。

for(:)循環中訪問stopThread是可選的;沒有它,它將不會中止,直到它完成了它所拾取的一攬子工作。

dataContainer是一組工作要做的std::vector或某些形式的工作。線程醒來,抓住所有待完成的工作,然後開始工作。

你也可以從dataContainer中彈出一個任務,而不是全部完成。由此產生的代碼更簡單。

要排隊的數據爲dataContainer,你必須鎖定mutex,把數據,然後通知:

{ 
    std::unique_lock<std::mutex> lock(mutex); 
    dataContainer.push_back(new_data); 
} 
cond.notify_one(); 

關閉:

{ 
    std::unique_lock<std::mutex> lock(mutex); 
    stopThread = true; 
} 
cond.notify_all(); 

請注意,即使stopThread是原子,你需要獲取互斥鎖。另外還有一個競賽條件。

+0

我喜歡如何拉出數據然後釋放鎖定,以便在處理當前數據時可以排隊更多條目。我可以在拉出數據後手動釋放鎖以獲得相同的效果嗎? –

+0

@ Mr.Boy當然,這可以工作。明確地解決鎖定狀態時要小心;有限範圍的鎖更容易推理。 – Yakk

相關問題