我有一个生产者 - 消费者安排来处理来自网络的事件。 Dispatcher
通过工作线程拥有的互斥锁保护队列为多个EventHandler
线程提供工作。放置在队列中的事件对象使用boost::intrusive_ptr
class Event { ... }
typedef boost::intrusive_ptr<Event> EventPtr;
队列是定义为的模板:
template<typename Data>
class ConcurrentQueue : boost::noncopyable
{
protected:
std::queue<Data> _queue;
boost::mutex _dataMutex;
boost::condition_variable _dataAvailable;
...
public:
...
void push(Data const& data)
{
boost::mutex::scoped_lock lock(_dataMutex);
_queue.push(data);
lock.unlock();
_dataAvailable.notify_one();
}
...
};
...
typedef ConcurrentQueue<EventPtr> EventQueue;
EventHandler
等待事件放入其队列,并在可用时使用方法waitAndPop
将其从队列中删除:
void waitAndPop(Data& poppedValue)
{
boost::mutex::scoped_lock lock(_dataMutex);
while(_queue.empty())
{
_dataAvailable.wait(lock);
}
poppedValue = _queue.front();
_queue.pop();
}
这很有效,但我需要确保Dispatcher
将相关工作提供给同一个EventHandler
。所以我实现了一个waitAndPeek
方法,将Event
对象留在队列中,但返回指向它的指针。
void waitAndPeek(Data& peekedValue)
{
boost::mutex::scoped_lock lock(_dataMutex);
while(_queue.empty())
{
_dataAvailable.wait(lock);
}
peekedValue = _queue.front();
}
一旦事件进动完成,事件就会从队列中弹出。将事件保留在队列中允许Disptacher检查队列头部的项目,以查看它是否与它尝试分配的项目相关。 (以互斥保护方式完成但未显示)
这是从EventQueue中提取指针的代码:
EventPtr event;
// Loop, processing events placed on the queue.
while (true)
{
// Blocking call. Will halt the thread until there is work to do.
_eventQueue->waitAndPeek(event);
// Try to access event but ASSERT fires
int id = event->getId();
...
}
问题是当我使用peeked指针时,intrusive_ptr
代码中会触发ASSERT。
/usr/local/packages/Boost/1.40.0/include/boost/smart_ptr/intrusive_ptr.hpp:166:
T* boost::intrusive_ptr<T>::operator->() const [with T = Event]:
Assertion `px != 0' failed.
只要我将代码恢复为使用waitAndPop
方法,问题就会消失,导致ASSERT触发的原因只是因为我将事件留在了队列中?
答案 0 :(得分:0)
看看intrusive_ptr docs:
http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/intrusive_ptr.html#indirection
为了取消引用它,它必须包含一个非NULL指针。