情况是这样的:
我正在处理通过套接字 Connection
接收的数据包,每个数据包都有一个不同的 ID 和一个通用类 Message
的相关子类(所以 FooMessage
, BarMessage
, HelloMessage
).
我需要使用这些消息来更新程序中的一些信息(信息存储在不同的类中,例如 AInformation
涉及所有与 A
相关的事物,BInformation
与 B
相关的事物,CInformation
等等...)。
为此,我引入了第三方:Listener
,它监听某些特定类型的消息并使用它们来更新与Listener
关联的信息类。所以我们有 AListener
来处理 FooMessage
和 BarMessage
,有一些特殊的功能可以更新 AInformation
,BListener
处理 BarMessage
和 HelloMessage
并更新 BInformation
...
这是通过我的套接字连接发送的 Message
的生命周期:
DuhMessage
由Connection
从Packet
(字节数组) 创建
DuhMessage
由Connection
发送给所有的监听器(我会解释我这一步的实现,这是我的问题)- 每个监听器都查看
DuhMessage
,如果更新监听器正在处理的信息类型很有趣,则消息由函数处理
第 2 步:
为了处理步骤2,我基本上在我的Connection
中有一个Listener
列表(这个列表必须是线程-安全,因为可以随时将 Listener
添加到 Connection
的列表中)。 Connection
锁定列表并将 DuhMessage
推送到所有 Listener
的消息队列。 (Listener
有一个消息队列,它一个接一个地消费它们,更新 Information
类)
这是我用 Dia 制作的总结它的模式:
我的问题是:
当我将 DuhMessage
推送到 Listener
的队列时,我应该复制该对象吗?因为我的 Listener
可以尝试同时读取 DuhMessage
的属性,不是吗?
这是我针对这种情况所做的线程安全双端队列实现(如果您可以验证它的话)。
#include <deque>
#include <memory>
#include <list>
#include <boost/thread.hpp>
#include "network/message.h"
#include "network/listener.h"
#include "utils/datastruct/listener_deque.h"
#ifndef LISTENER_DEQUE_H
#define LISTENER_DEQUE_H
/**
* Thread-Safe listener deque. Allow to add listeners and send messages to
* listeners
*/
class ListenerDeque
{
public:
ListenerDeque ();
virtual ~ListenerDeque ();
/**
* Add one listener to the deque
*/
void push(std::shared_ptr<Listener> listener);
/**
* Add multiple listeners to the deque
*/
void push(std::list<std::shared_ptr<Listener>> listeners);
/**
* Send a message to all listeners
*/
void send(std::unique_ptr<Message> message);
/**
* Returns whether the deque is empty or not
*/
bool empty();
/**
* Returns the number of listeners in the deque
*/
int size();
private:
std::deque<std::shared_ptr<Listener>> listeners;
mutable boost::mutex mutex;
};
#endif
bool ListenerDeque::empty()
{
boost::mutex::scoped_lock lock(this->mutex);
return this->listeners.empty();
}
int ListenerDeque::size()
{
boost::mutex::scoped_lock lock(this->mutex);
return this->listeners.size();
}
void ListenerDeque::push(std::list<std::shared_ptr<Listener> > listeners)
{
typedef std::list<std::shared_ptr<Listener> >::iterator iterator;
boost::mutex::scoped_lock lock(this->mutex);
for (iterator it = listeners.begin(); it != listeners.end(); ++it)
this->listeners.push_back(*it);
}
void ListenerDeque::push(std::shared_ptr<Listener> listener)
{
boost::mutex::scoped_lock lock(this->mutex);
this->listeners.push_back(listener);
}
void ListenerDeque::send(std::unique_ptr<Message> message)
{
typedef std::deque<std::shared_ptr<Listener> >::iterator iterator;
boost::mutex::scoped_lock lock(this->mutex);
for (iterator it = this->listeners.begin();
it != this->listeners.end(); ++it)
{
std::unique_ptr<Message> m (message.copy());
(*it)->push(m);
}
}
最佳答案
- 如果消息和监听器之间存在一对一的关联,您可以在单个 thead 中进行消息到监听器的限定,将消息移动到适当的监听器,在这种情况下没有并发访问。
- 如果一条消息可以发送给多个监听器,则向他们发送“const DuhMessage *”,他们将无法以任何方式修改消息属性,因此并发读取访问将是安全的。 唯一的问题是谁将删除 DuhMessage,使用 ref_count 等。
关于c++ - 将对象添加到监听器队列时是否需要复制对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22856004/