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

Access member variable in one thread only, but not the thread of the class instance

我面临以下问题:

我有一个RpcExecutorclass。这个class:

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

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

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

我开始在与 async_read_until 相同的套接字中收听,然后回复来了,可能是乱序的。我还需要从这个 hanlder 修改 pendingRequests_

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

我的 class 看起来像这样:

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

为了保证pendingRequests_的初始化,pendingRequests_的读写都是通过同一个线程完成的(我查过是这样的),我有应用了以下限制:

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

总而言之:

结果

问题

  1. 考虑到 RpcExecutor class 实例在另一个线程中,我应该如何初始化可以从我的处理程序线程使用的 map?即使我通过 post 在与 asio::context::run 相同的线程中初始化指向的元素,处理程序仍然看到对象的不同地址。
  2. 我需要任何类型的互斥量吗?实际上,我想从单个线程执行所有 reads/writes,即使与 RpcExecutor class 实例不同的线程,它保存 pendingTasks_ 成员变量。

问题很微妙:

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

executor_ = RpcExecutor(socket_);

然后创建了RpcExecutor,开始监听传入的消息,所有这些都在构造函数中。但是那个对象在那之后被移动到 executor_ 变量。

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

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

解决方案

  1. 为安全起见,使 RpcExecutor 不可复制且不可移动。
  2. 我还认为显式调用 RpcExecutor::listenIncomingMessage 是个好主意。