I have implemented a basic threaded producer-consumer (thread 1 = producer, thread 2 = consumer) using Boost threads and conditions. I am getting stuck in wait() indefinitely quite often. I can’t really see what could be wrong here. Below is some pseudo-code:
// main class
class Main {
public:
void AddToQueue(...someData...)
{
boost::mutex::scoped_lock lock(m_mutex);
m_queue.push_back(new QueueItem(...someData...));
m_cond.notify_one();
}
void RemoveQueuedItem(...someCond...)
{
// i'm wondering if this could cause the trouble?
boost::mutex::scoped_lock lock(m_mutex);
// erase a item matching condition (some code not shown,
// but should be fairly self-explanatory -- IsMatch()
// simply looks at a flag of QueueItem
m_queue.erase(std::remove_if(m_queue.being(), m_queue.end(),
boost::bind(&Main::IsMatch, this, _1, someCond), m_queue.end());
}
friend void WorkerThread(Main* m);
private:
boost::ptr_deque<QueueItem> m_queue;
boost::mutex m_mutex;
boost::condition m_cond;
};
// worker thread
void WorkerThread(Main* m)
{
typedef boost::ptr_deque<QueueItem>::auto_type RelType;
RelType queueItem;
while(!shutDown) {
{ // begin mutex scope
boost::mutex::scoped_lock lock(m->m_mutex);
while(m->m_queue.empty()) {
m->m_cond.wait(lock); // <- stuck here forever quite often!
}
queueItem = m->m_queue->pop_front(); // pop & take ptr ownership
} // end mutex scope
// ... do stuff with queueItem
// ...
// ... queueItem is deleted when it leaves scope & we loop around
}
}
Some additional information:
- Using Boost v1.44
- Issue is occurring in Linux and Android; I’m not yet sure if it happens in Windows
Any ideas?
UPDATE:
I believe I have isolated the issue. I’ll update further once confirmed, which hopefully will be tomorrow.
UPDATE 2:
It turns out there is no issue in the code described above. I was reliant on a underlying API for AddToQueue() – when processing data in the worker thread & handing it back to the API, it had a circular bug where it would call AddToQueue() again… which is now fixed 😉
I did something similar recently even though mine uses the STL queue. See if you can pick out from my implementation. As wilx says, you need to wait on the condition. My implementation has maximum limit on the elements in the queue and I use that to wait for the mutex/guard to be freed.
I originally did this on Windows with ability to use Mutex or Critical sections in mind hence the template parameter which you can remove and use
boost::mutexdirectly if it simplifies it for you.This way, you can share the queue across the producer/consumer. Example usage
With Producer/Consumer defined as below