我创建了一个用于多线程应用程序的通用消息队列。具体来说,单一生产者,多消费者。主要代码如下。
1)我想知道我是否应该将一个用 new 分配的 shared_ptr 按值传递给 enqueue 方法,还是让队列包装器自己分配内存并通过 const 引用传入一个 genericMsg 对象更好?
2) 我应该让我的 dequeue 方法返回一个 shared_ptr,让一个 shared_ptr 通过引用作为参数传入(当前策略),还是让它直接返回一个 genericMsg 对象?
3) 我需要在入队/出队时发出信号/等待,还是读/写锁就足够了?
4) 我什至需要使用 shared_ptrs 吗?还是这仅取决于我使用的实现?我喜欢一旦所有引用不再使用该对象,shared_ptrs 将释放内存。不过,如果推荐的话,我可以轻松地将其移植到常规指针。
5)我在这里存储一对,因为我想区分我正在处理的消息类型,否则不必执行any_cast。每个消息类型都有一个唯一的 ID,它引用一个特定的结构。有没有更好的方法来做到这一点?
通用消息类型:
template<typename Message_T>
class genericMsg
{
public:
genericMsg()
{
id = 0;
size = 0;
}
genericMsg (unsigned int &_id, unsigned int &_size, Message_T &_data)
{
id = _id;
size = _size;
data = _data;
}
~genericMsg()
{}
unisgned int id;
unsigned int size;
Message_T data; //All structs stored here contain only POD types
};
入队方法:
// ----------------------------------------------------------------
// -- Thread safe function that adds a new genericMsg object to the
// -- back of the Queue.
// -----------------------------------------------------------------
template<class Message_T>
inline void enqueue(boost::shared_ptr< genericMsg<Message_T> > data)
{
WriteLock w_lock(myLock);
this->qData.push_back(std::make_pair(data->id, data));
}
对比:
// ----------------------------------------------------------------
// -- Thread safe function that adds a new genericMsg object to the
// -- back of the Queue.
// -----------------------------------------------------------------
template<class Message_T>
inline void enqueue(const genericMsg<Message_T> &data_in)
{
WriteLock w_lock(myLock);
boost::shared_ptr< genericMsg<Message_T> > data =
new genericMsg<Message_T>(data_in.id, data_in.size, data_in.data);
this->qData.push_back(std::make_pair(data_in.id, data));
}
出队方法:
// ----------------------------------------------------------------
// -- Thread safe function that grabs a genericMsg object from the
// -- front of the Queue.
// -----------------------------------------------------------------
template<class Message_T>
void dequeue(boost::shared_ptr< genericMsg<Message_T> > &msg)
{
ReadLock r_lock(myLock);
msg = boost::any_cast< boost::shared_ptr< genericMsg<Message_T> > >(qData.front().second);
qData.pop_front();
}
获取消息 ID:
inline unsigned int getMessageID()
{
ReadLock r_lock(myLock);
unsigned int tempID = qData.front().first;
return tempID;
}
数据类型:
std::deque < std::pair< unsigned int, boost::any> > qData;
编辑:
我改进了我的设计。我现在有一个 genericMessage 基类,我直接从其子类化以派生唯一消息。
通用消息基类:
class genericMessage
{
public:
virtual ~genericMessage() {}
unsigned int getID() {return id;}
unsigned int getSize() {return size;}
protected:
unsigned int id;
unsigned int size;
};
制片人片段:
boost::shared_ptr<genericMessage> tmp (new derived_msg1(MSG1_ID));
theQueue.enqueue(tmp);
消费者片段:
boost::shared_ptr<genericMessage> tmp = theQueue.dequeue();
if(tmp->getID() == MSG1_ID)
{
boost::shared_ptr<derived_msg1> tObj = boost::dynamic_pointer_cast<derived_msg1>(tmp);
tObj->printData();
}
新队列:
std::deque< boost::shared_ptr<genericMessage> > qData;
新入队:
void mq_class::enqueue(const boost::shared_ptr<genericMessage> &data_in)
{
boost::unique_lock<boost::mutex> lock(mut);
this->qData.push_back(data_in);
cond.notify_one();
}
新出队:
boost::shared_ptr<genericMessage> mq_class::dequeue()
{
boost::shared_ptr<genericMessage> ptr;
{
boost::unique_lock<boost::mutex> lock(mut);
while(qData.empty())
{
cond.wait(lock);
}
ptr = qData.front();
qData.pop_front();
}
return ptr;
}
现在,我的问题是我是否正确地出队?还有另一种方法吗?在这种情况下,我应该传入一个 shared_ptr 作为参考来实现我想要的吗?