在生产者-消费者代码中使用 wait() 增强条件死锁
我使用 Boost 线程和条件实现了一个基本的线程生产者-消费者(线程 1 = 生产者,线程 2 = 消费者)。我经常无限期地陷入 wait() 状态。我实在看不出这里有什么问题。下面是一些伪代码:
// 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
}
}
一些附加信息:
- 使用 Boost v1.44
- Linux 和 Android 中发生 问题;我还不确定 Windows 中是否会发生这种情况
有什么想法吗?
更新: 我相信我已经隔离了这个问题。一旦确认,我将进一步更新,希望是明天。
更新2: 事实证明,上述代码没有问题。当在工作线程中处理数据时,我依赖于 AddToQueue() 的底层 API。将其交还给 API 时,它有一个循环错误,它会再次调用 AddToQueue()...现已修复;-)
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 ;-)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我最近做了类似的事情,尽管我使用的是 STL 队列。看看你能不能从我的实现中挑出来。正如 wilx 所说,您需要等待条件。我的实现对队列中的元素有最大限制,我用它来等待互斥体/防护被释放。
我最初在 Windows 上执行此操作,考虑到能够使用互斥体或关键部分,因此您可以直接删除并使用
boost::mutex
模板参数(如果它可以为您简化的话)。这样,您可以在生产者/消费者之间共享队列。 生产者/消费者的使用示例
如下定义
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::mutex
directly 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
应该是:
你死锁了你的类,因为你仍然获得了互斥锁,但你在等待。所有其他方法都希望获取相同的互斥锁并等待永远不会释放互斥锁的工作线程。
should be:
You dead locked your classs because you had still the mutex accquired but you were waiting. Every other method wants to accquire the same mutex and wait for your worker which will never release the mutex.