[英]std::condition_variable::wait in c++
我對互斥鎖、鎖定和等待有點困惑。
這是我的代碼:
void producer(std::mutex* m, std::condition_variable* cv,bool* signal) {
std::this_thread::sleep_for(std::chrono::seconds(1));
m->lock();
*signal = true;
m->unlock();
std::this_thread::sleep_for(std::chrono::seconds(3));
cv->notify_one();
printf("notify one\n");
std::this_thread::sleep_for(std::chrono::seconds(10000));
}
void consumer(std::mutex*m, std::condition_variable* cv, bool* signal, int index) {
if(index == 2) std::this_thread::sleep_for(std::chrono::seconds(2));
std::unique_lock<std::mutex> lk(*m);
cv->wait(lk, [&] { return (*signal); });
printf("consumer %d passes this point!\n", index);
std::this_thread::sleep_for(std::chrono::seconds(10000));
}
int main() {
bool signal = false;
std::mutex m;
std::condition_variable cv;
std::thread th1(producer, &m, &cv, &signal);
std::thread th2(consumer, &m, &cv, &signal, 1);
std::thread th3(consumer, &m, &cv, &signal, 2);
th1.join();
th2.join();
th3.join();
return 0;
}
添加了std::this_thread::sleep_for
來解釋我的問題。 有生產者、消費者1和消費者2。我認為這段代碼應該如下工作:
std::unique_lock<std::mutex> lk(*m);
所以它鎖定。cv->wait
。 因為signal
的初始值為false
,所以 consumer1 被阻塞並釋放鎖。m->lock();
, *signal = true;
, m->unlock();
和sleep_for
。 因此, signal
變為true
。std::unique_lock<std::mutex> lk(*m);
和cv->wait(lk, [&] { return (*signal); });
. 因為signal
是true
,所以這個線程只是通過它。 所以, printf("consumer %d passes this point,\n"; index);
被執行。cv->notify_one();
. 消費者 1 已解鎖並檢查情況。 因為signal
是ture
,所以 consumer1 可以通過這一點。 因此, consumer1 滿足printf
。因此,我的預期結果是
consumer 2 passes this point!
notify one
consumer 1 passes this point!
然而,真正的結果是
consumer 2 passes this point!
notify one
好像consumer1不能通過cv->wait(lk, [&] { return (*signal); });
,即使notify_one()
被調用並且條件得到滿足。 我的理解有什么問題嗎?
您沒有釋放consumer
程序中的鎖定。 下面的代碼符合預期:
#include <thread>
#include <chrono>
#include <condition_variable>
#include <mutex>
void producer(std::mutex* m, std::condition_variable* cv,bool* signal) {
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::unique_lock<std::mutex> lk(*m);
*signal = true;
}
std::this_thread::sleep_for(std::chrono::seconds(3));
cv->notify_all();
printf("notify one\n");
std::this_thread::sleep_for(std::chrono::seconds(5));
}
void consumer(std::mutex*m, std::condition_variable* cv, bool* signal, int index) {
if(index == 2) std::this_thread::sleep_for(std::chrono::seconds(2));
{
std::unique_lock<std::mutex> lk(*m);
cv->wait(lk, [&] { return (*signal); });
}
printf("consumer %d passes this point!\n", index);
std::this_thread::sleep_for(std::chrono::seconds(5));
}
int main() {
bool signal = false;
std::mutex m;
std::condition_variable cv;
std::thread th1(producer, &m, &cv, &signal);
std::thread th2(consumer, &m, &cv, &signal, 1);
std::thread th3(consumer, &m, &cv, &signal, 2);
th1.join();
th2.join();
th3.join();
return 0;
}
注意std::unique_lock<std::mutex> lk(*m);
周圍的括號。 提供本地scope。
問題是消費者 2 在進入睡眠狀態之前沒有釋放互斥鎖上的鎖:
std::unique_lock<std::mutex> lk(*m);
cv->wait(lk, [&] { return (*signal); });
printf("consumer %d passes this point!\n", index); // <-- mutex is still locked here
std::this_thread::sleep_for(std::chrono::seconds(10000));
因此,即使消費者 1 中的條件可能滿足,它也無法獲取互斥鎖上的鎖,因為它已經被另一個線程鎖定。
與對應的std::lock_guard
相比, std::unique_lock為您提供了更細粒度的控制,包括解鎖能力。 您可以做的是在消費者進入睡眠之前添加一個解鎖調用,如下所示:
...
lk.unlock();
std::this_thread::sleep_for(std::chrono::seconds(10000));
否則,只有在消費者 2 執行完consumer()
function 后,即長時間休眠后,才會釋放互斥鎖上的鎖。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.