我有以下問題。我有一些多線程可以完成一些工作,一個主線程可以在工作時喚醒它們。到目前爲止,我已經設法使用條件變量和互斥鎖編寫一些代碼,並且大部分時間都可以正常工作,但通知線程不時會在調用notify_one()後立即鎖定互斥鎖,從而阻止通知的線程和死鎖。notify_one()(通知線程鎖互斥)後的死鎖
我寫了最小的代碼來說明這種情況。
#include <iostream>
#include <thread>
#include <condition_variable>
std::mutex lock;
std::condition_variable cv;
void foo() {
std::cout << "Thread: Entering doWork()" << std::endl;
std::unique_lock<std::mutex> l(lock);
std::cout << "Thread: Acquired lock, going to wait." << std::endl;
cv.wait(l , []{return true;});
std::cout << "Thread: Done waiting, exit." << std::endl;
}
int main(void) {
std::unique_lock<std::mutex> l(lock);
std::cout << "MAIN: Creating thread." << std::endl;
std::thread t(foo);
std::cout << "MAIN: Unlocking mutex." << std::endl;
l.unlock();
std::cout << "MAIN: Notifying thread." << std::endl;
cv.notify_one();
//std::this_thread::sleep_for(std::chrono::seconds(1));
l.lock();
std::cout << "MAIN: Acquired lock." << std::endl;
std::cout << "MAIN: Joining thread." << std::endl;
t.join();
return 0;
}
在理想的情況下,輸出應該是
MAIN: Creating thread.
MAIN: Unlocking mutex.
Thread: Entering doWork()
Thread: Acquired lock, going to wait.
MAIN: Notifying thread.
Thread: Done waiting, exit.
MAIN: Acquired lock.
MAIN: Joining thread.
,但往往不是它是
MAIN: Creating thread.
MAIN: Unlocking mutex.
MAIN: Notifying thread.
MAIN: Acquired lock.
MAIN: Joining thread.
Thread: Entering doWork()
是否有消除僵局的機會,只是加入的睡眠沒有更好的辦法進入通知線程(我不想這樣做)?先謝謝你。
您的'cv.wait()'不處理虛假的喚醒。根據http://en.cppreference.com/w/cpp/thread/condition_variable/wait:原子釋放鎖,阻塞當前正在執行的線程,並將其添加到等待* this的線程列表中。當執行notify_all()或notify_one()時,線程將被解除阻塞。它也可能被虛假地阻止。無阻塞時,無論原因如何,都會重新獲得鎖定並等待退出。 –
你已經錯過了'notify' /'wait'方案的整個邏輯!你忘了執行你正在等待的東西,它的變化線程需要被通知!你有一個'wait',它不會等待*任何事情和一個不通知任何事情的'notify'! –
@AndrewHenle,線程確實釋放了鎖,這就是'unique_lock'的用途。如果它測試了一個適當的條件,而不是'[] {return true;}',它會處理虛假的喚醒,因爲謂詞在喚醒時會被測試,如果謂詞是false,它會再次等待。 –