I have a producer thread which produces work for three consumer threads. When work has been produced, the producer thread waits until the consumer threads have finished handling the work. The producer thread then goes on handling the results.
#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();
}
}
The problem is that I need to make sure that all consumer threads have entered cond.wait(lock)
before the producer thread starts its next iteration:
- All 4 threads have reached the barrier. The barrier gets released and the threads can continue.
- The producer thread locks the mutex before all consumer threads have reached
cond.wait(lock)
. Thus at least one consumer thread is blocked bylock.lock()
. - The producer thread starts its next iteration, creates work and notifies the consumers. Since at least one consumer thread has not yet reached
cond.wait(lock)
thenotify_all()
will be missed by at least one consumer thread. These threads now wait for the nextnotify_all()
- which will never arrive. - The next time the barrier is reached, at least one consumer thread still waits for the next
notify_all()
. Thus the barrier will not be unlocked and a deadlock occured.
How can I resolve this situation?
produce work => wait until all work resolved => combine the results.
enough? – apple apple