开发者

Assert fires in boost::intrusive_ptr when used in a container

I have a Producer-Consumer arrangement to process events coming from the network. A Dispatcher gives work to multiple EventHandler threads via a mutex protected queue owned by the worker thread. The event objects placed in the queue use boost::intrusive_ptr

class Event { ... }
typedef boost::intrusive_ptr<Event> EventPtr;

The queue is a template defined as:

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;

The EventHandler waits for an event to be put on its queue and when available removes it from the queue using the method waitAndPop:

void waitAndPop(Data& poppedValue)
{
    boost::mutex::scoped_lock lock(_dataMutex);
    while(_queue.empty())
    {
        _dataAvailable.wait(lock);
    }
    poppedValue = _queue.front();
    _queue.pop();
}

This was working well but I then needed to ensure the Dispatcher gives related work to the same EventHandler. So I implemented a waitAndPeek method to leave the Event object on the queue but return the pointer to it.

void waitAndPeek(Data& peekedValue)
{
    boost::mutex::scoped_lock lock(_dataMutex);
    while(_queue.empty())
    {
        _dataAvailable.wait(lock);
    }
    peekedValue = _queue.front();
}

Once precessing of the event is complete the event is popped off the queue. Leaving the event on the queue allows the Disptacher to check the item at the head of the queue to see if it is related to the one it is trying to allocate. (Done in a mutex protected way but not shown)

Here's the code extracting the pointer from the 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();
    ...
}

The problem is an ASSERT is fired in the intrusive_ptr code when I use the peeked pointer.

/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.

As soon as I revert the code to use the waitAndPop method the problem goes away, what could be causing the ASSERT to fire just because I leave the event on the开发者_高级运维 queue?


Look at intrusive_ptr docs:

http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/intrusive_ptr.html#indirection

In order to dereference it, it must hold a non-NULL pointer.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜