У меня есть договоренность между производителем и потребителем для обработки событий, поступающих из сети.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();
}
После завершения обработки события событие удаляется из очереди.Оставление события в очереди позволяет Диспетчеру проверить элемент в начале очереди, чтобы увидеть, относится ли он к тому, который он пытается выделить.(Сделано защищенным мьютексом способом, но не показано)
Вот код, извлекающий указатель из 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();
...
}
Проблема в том, что ASSERT запускается в коде intrusive_ptr
, когдаЯ использую заглядывающий указатель.
/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 только потому, что я оставляю событие наочередь?