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



我面临以下问题:

我有一个RpcExecutor课。此类:

  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 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是同一线程。

总而言之:

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

结果

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

问题

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

问题非常微妙:

我在代码的某行中执行此操作:

executor_ = RpcExecutor(socket_);

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

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

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

溶液

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

最新更新