仅在一个线程中访问成员变量,而不在类实例的线程中访问成员变量

时间:2018-12-12 11:29:33

标签: multithreading c++11 networking boost-asio

我面临以下问题:

我有一个RpcExecutor班。此类:

  1. 发送rpc请求
  2. 接收rpc响应

我将所有内容保持异步(通过boost.asio)。每次发送请求时,都会调用写处理程序来修改映射:

async_write(...., [this, ...](error_code ec, size_t bytesTransferred) {
                    //
                    pendingRequests_.insert(requestId, move(myPromise));
           };

我开始使用async_read_until在同一个套接字中进行侦听,并且答复可能不正确。我还需要从此程序中修改pendingRequests_

async_read(... [this, ...](error_code ec, size_t bytesTransferred) {
                  ...
                  pendingRequests_.at(requestId).set_value(...);
                  pendingRequests_.erase(requestId);
});

我的课看起来像这样:

class RpcExecutor {
private:
      std::unique_ptr<std::map<std::uint64_t, MyPromise>> pendingRequests_;
      ...
};

为了确保pendingRequests_的初始化,pendingRequests_的读取和写入是通过同一线程完成的(我确实检查了这种情况),我有以下限制已应用:

  1. 有一个运行的asio::run()线程,与RpcExecutor实例不同。
  2. 我在pendingRequests_内初始化boost::asio::post(myIoContext, ...)指向对象,这意味着它在执行asio::run的同一线程中初始化。
  3. async_read处理程序和async_write处理程序在与io_context::run相同的线程中执行,而该线程与boost::asio::post相同。

总共:

  • boost::asio::postasync_read处理程序和async_write处理程序在同一线程中执行。
  • RpcExecutor类实例是在另一个线程中创建的。

结果

  • async_readasync_write处理程序看不到pendingRequests_的相同内存地址。

问题

  1. 考虑到map类实例在另一个线程中,我应该如何初始化我的处理程序线程中可以使用的RpcExecutor?即使我通过asio::context::run在与post相同的线程中初始化了指向元素,处理程序仍然看到该对象的不同地址。
  2. 我需要任何种类的互斥锁吗?实际上,我希望从单个线程进行所有读/写操作,即使与包含RpcExecutor成员变量的pendingTasks_类实例不是同一线程也是如此。

1 个答案:

答案 0 :(得分:0)

问题非常微妙:

我在代码的某些行中这样做:

executor_ = RpcExecutor(socket_);

然后创建RpcExecutor,开始监听传入的消息,所有消息都在构造函数中。但是此后该对象被移至executor_变量。

由于我的async_readasync_read处理程序正在捕获this,并且this在移动后不是同一地址,因此它们显示了不同的地址:

  • 读取的传入消息显示了原始对象this
  • 外发邮件显示了已经移动的this地址。

解决方案

  1. 为了安全起见,使RpcExecutor不可复制且不可移动。
  2. 我还认为明确地致电RpcExecutor::listenIncomingMessage是个好主意。