c++ - 将对象添加到监听器队列时是否需要复制对象?

标签 c++ multithreading data-structures mutex

情况是这样的:

我正在处理通过套接字 Connection 接收的数据包,每个数据包都有一个不同的 ID 和一个通用类 Message 的相关子类(所以 FooMessage, BarMessage, HelloMessage).

我需要使用这些消息来更新程序中的一些信息(信息存储在不同的类中,例如 AInformation 涉及所有与 A 相关的事物,BInformationB 相关的事物,CInformation 等等...)。

为此,我引入了第三方:Listener,它监听某些特定类型的消息并使用它们来更新与Listener 关联的信息类。所以我们有 AListener 来处理 FooMessageBarMessage,有一些特殊的功能可以更新 AInformationBListener 处理 BarMessageHelloMessage 并更新 BInformation...

这是通过我的套接字连接发送的 Message 的生命周期:

  1. DuhMessageConnectionPacket(字节数组)
  2. 创建
  3. DuhMessageConnection 发送给所有的监听器(我会解释我这一步的实现,这是我的问题)
  4. 每个监听器都查看 DuhMessage,如果更新监听器正在处理的信息类型很有趣,则消息由函数处理

第 2 步:

为了处理步骤2,我基本上在我的Connection 中有一个Listener 列表(这个列表必须是线程-安全,因为可以随时将 Listener 添加到 Connection 的列表中)。 Connection 锁定列表并将 DuhMessage 推送到所有 Listener 的消息队列。 (Listener 有一个消息队列,它一个接一个地消费它们,更新 Information 类)

这是我用 Dia 制作的总结它的模式:

enter image description here

我的问题是:

当我将 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);
    }
}

最佳答案

  1. 如果消息和监听器之间存在一对一的关联,您可以在单个 thead 中进行消息到监听器的限定,将消息移动到适当的监听器,在这种情况下没有并发访问。
  2. 如果一条消息可以发送给多个监听器,则向他们发送“const DuhMessage *”,他们将无法以任何方式修改消息属性,因此并发读取访问将是安全的。 唯一的问题是谁将删除 DuhMessage,使用 ref_count 等。

关于c++ - 将对象添加到监听器队列时是否需要复制对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22856004/

相关文章:

java - TreeSet 中的值更改后不会重新排序

arrays - 吸引力作为编码

C++ 无法使用 g++-mp-4.4 捕获从 Mac OS 中的 curlpp 抛出的异常

c - 使用多线程时保护全局变量

java - 从 JedisPool 获取资源时线程处于等待状态

java - 可变原子引用是个坏主意吗?

java - 使用数组对有界集进行添加/删除操作的最坏情况的时间复杂度?

c++ - 模 : The Purpose of An Undefined Integer

用于第 3 方库调用的 C++ 看门狗

c++ - 将类对象转换为字符串