使用通知全部进行多次等待

Multiple wait using notify all

本文关键字:等待 通知 全部      更新时间:2023-10-16

我希望在等待中使用条件变量。

我创建了一个包含 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();
}

这不是条件变量的工作方式。

要认识到的主要事情是,条件变量本身不能可靠地发出事件信号。特别是,wait()呼叫可能会虚假返回,也就是说,没有人呼叫notify

相反,您需要的是条件变量绑定到的周围程序中的逻辑条件。只要条件更改,就可以调用通知,并通过提供检查器谓词函数作为调用的参数来检查条件,wait作为周围循环的一部分或在wait内部检查条件。

另一个需要注意的问题是,虽然等待不能在没有通知的情况下继续(从逻辑上讲,假设没有虚假的唤醒(,但相反的情况并非如此。也就是说,go()函数甚至可以在print_id函数到达第一个等待之前运行完成。然后,该等待将被永久阻止,因为途中不再有通知。通知不要等待等待,它们是即发即弃操作。

在正确使用条件变量时,这不是问题,因为等待只是等待逻辑条件更改。如果该更改已在等待调用之前发生,则您检测到它,并且首先不要调用等待。

您可能在这里想要的是障碍的行为。您可以使用int计数器作为条件以及同步condition_variablemutex,轻松实现自己的屏障。