У меня есть класс с именем'метарная подписка '. Этот класс получает свои данные через подписанные издатели (множественное число), вызывающие его метод push.
В другом потоке метод pop этого класса вызывается для получения этих данных.
Таким образом, в некотором смысле этот класс является своего рода буфером между несколькими издателями и их подписчиками. Для реализации я основывался на информации, найденной о поточно-ориентированных очередях здесь .
Теперь мой вопрос двоякий:
- Если бы я использовал один и тот же мьютекс для ввода и вывода значений (в настоящее время я использую два разных мьютекса), возможно ли, что моя программа застрянет, ожидая заблокированного нажатия?
- Если нет, то как методы push и pop могут преодолеть блокировку (the_same_mutex).
Я предполагаю, что, если бы я использовал тот же мьютекс и программа вошла в метод pop, она получила бы блокировку pop, проверила, пуста ли очередь, и подождала переменную условия, которая никогда не может быть установлена в метод push (так как блокировка уже получена pop).
текущий код (с использованием двух разных мьютексов):
#include <boost/thread.hpp>
#include <queue>
#include "subscriber.h"
#include "pubdata.h"
#ifdef DEBUG
#include <iostream>
#include <boost/lexical_cast.hpp>
#endif
namespace PUBLISHSUBSCRIBE
{
template<class T>
class SubscribedQueue: public PUBLISHSUBSCRIBE::Subscriber<T>, private std::queue< PubData<T> >
{
public:
PubData<T> pop(); //removes the next item from the queue, blocks until the queue is not empty
void push(const PubData<T> data); //method used by the publisher to push data onto the queue
private:
mutable boost::mutex writeMutex_; //only needed for publishing/pushing data
mutable boost::mutex readMutex_; //only needed for reading/popping data
boost::condition_variable notify_;
};
template<class T>
PubData<T> SubscribedQueue<T>::pop() { //Blocks until the queue is not empty
boost::mutex::scoped_lock lock(readMutex_);
while(std::queue< PubData<T> >::empty())
notify_.wait(lock); //block until recieving a notification AND the queue is not empty
PubData<T> head = std::queue< PubData<T> >::front();
std::queue< PubData<T> >::pop();
#ifdef DEBUG
std::string debugOut("pop: " + boost::lexical_cast<std::string>(head) + " - timestamp: " + boost::lexical_cast<std::string>(head.timestamp()) + " - from: " + boost::lexical_cast<std::string>(this) + "\n" );
std::cout <<debugOut;
#endif
lock.unlock();
return head;
}
template<class T>
void SubscribedQueue<T>::push(const PubData<T> data){
boost::mutex::scoped_lock lock(writeMutex_);
#ifdef DEBUG
std::cout << "published: " << data << std::endl;
#endif
std::queue< PubData<T> >::push(data);
lock.unlock();
notify_.notify_one();
}
}
#endif //SUBSCRIBEDQUEUE_H
[править] Что меня больше всего беспокоит, так это то, что у меня есть boost :: condition_variable notify_, для которого в pop-режиме выполняется ожидание уведомления.
Но pop должен сначала заблокировать мьютекс, тот же мьютекс, который также должен быть заблокирован в «push», чтобы «уведомить» условную переменную.
Так не приведет ли это к тупику, а почему бы и нет?