我有一个生产者线程,可以为三个消费者线程生成工作。生成工作后,生产者线程将等待,直到消费者线程完成处理工作。然后生产者线程继续处理结果。
#include <condition_variable>
#include <mutex>
#include <boost/thread/barrier.hpp>
#include <vector>
#include <queue>
std::condition_variable cond;
std::mutex mutex;
boost::barrier barrier(4);
std::vector<std::thread> workers;
std::queue<unsigned int> work;
std::queue<unsigned int> results;
void worker();
int main()
{
// 1 producer and 3 consumers
for(unsigned int i = 0; i < 3; i++)
workers.push_back(std::thread(worker));
// Wait here so the three workers can get to cond.wait();
barrier.wait();
std::unique_lock<std::mutex> lock(mutex);
while(true)
{
// Generate work
std::cout << "gen" << std::endl;
for(unsigned int i = 0; i < 10; i++)
work.push(i);
cond.notify_all();
lock.unlock();
barrier.wait();
// Handle the results
while(results.size() > 0)
results.pop();
lock.lock();
}
return 0;
}
void worker()
{
while(true)
{
std::unique_lock<std::mutex> lock(mutex);
while(results.size() == 0)
{
lock.unlock();
barrier.wait();
lock.lock();
cond.wait(lock);
}
// Get work
unsigned int next = work.front();
work.pop();
// Store the result
results.push(next);
lock.unlock();
}
}
问题是我需要确保所有使用者线程在生产者线程开始下一次迭代之前已经输入cond.wait(lock)
:
cond.wait(lock)
之前锁定互斥锁。因此,lock.lock()
阻止了至少一个消费者线程。cond.wait(lock)
,因此至少一个消费者线程将错过notify_all()
。这些线程现在等待下一个notify_all()
- 它永远不会到达。notify_all()
。因此屏障不会被解锁并发生死锁。我该如何解决这种情况?
答案 0 :(得分:1)
condition_variable应与标志一起使用,以帮助防止虚假唤醒。同样的标志也可用于检查线程是否应该等待或直接工作。
添加bool go_to_work=false;
,然后我们只需在调用wait
时将其添加为谓词,并确保我们在主线程中设置/取消设置它。
在调用notify_all之前的主线程中,我们设置了bool
go_to_work=true;
cond.notify_all();
在我们的工作线程中,我们将谓词添加到wait
调用
cond.wait(lock, [](){ return go_to_work; });
最后,在我们的主线程中,我们希望在完成所有工作后将标志设置为false。
barrier.wait();
lock.lock(); // We need to lock the mutex before modifying the bool
go_to_work=false;
lock.unlock();
//Handle result...
现在,如果一个线程在主线程设置wait
后到达go_to_work=true
调用,它将不会等待,只需继续进行即可。作为奖励,这也可以防止虚假的唤醒。