【问题标题】:Does asio::io_service::post make happen-before relationship?asio::io_service::post 是否建立先发生关系?
【发布时间】:2015-11-10 22:57:35
【问题描述】:
boost::shared_ptr<A> a = boost::shared_ptr<A>(new A);
a->i = 2;
strand.post([a](){assert(a->i == 2)});

或

io_service.post([a](){assert(a->i == 2)});

当我在 thread1 中向 strand 或 io_service 发布处理程序时,执行处理程序的 thread2 是否在发布之前看到数据更改?

Java 也有类似的 Executor 来建立前发生关系:

在提交 Runnable 之前线程中的操作 执行者发生-在其执行开始之前。同样适用于可调用对象 提交给 ExecutorService。

asio 呢?

请注意,此问题不询问已发布到 io_service 或 strand 的处理程序的执行顺序。 Asio doc 表示如果使用 strand,则 post(a) 发生在 post(b) 之前。但是这个问题问:(编码顺序)post(a)之前的动作是否发生在post(a)之前(处理程序a的执行)?这是关于内存模型的。让我澄清一下:

// in thread1
global variable a = 111;
start a new thread2 which will access global variable a

我们知道线程 1 中的动作在线程 2 开始之前发生在线程 2 开始之前。这意味着: 1、最终执行顺序与代码顺序相同(编译器或CPU不会改变顺序)。 2、global variable a值设置动作将刷新到主内存(或同步到thread2的CPU缓存),然后thread2将更新为global variable a的最新值(当然,直到它开始)。

asio 的帖子与这个例子类似,所以我问了这个问题。我认为 asio 的帖子应该先发生关系,否则它将毫无用处。但我不确定,我想知道 asio 是怎么做到的。

要让happen-before,有3种方式:1、线程启动、加入。 2、锁定和解锁互斥量。 3、内存屏障。

【问题讨论】:

  • 让我们澄清一下:您认为a-&gt;i = 2; 可能会在 strand.post 之后执行?
  • 是的。但是还有其他情况:执行顺序和代码顺序一样,但是thread2读不到a->i的最新值集。如果没有发生之前的关系,它们都可能发生
  • 请注意,如果您正确使用链,则帖子“来自同一链”,因此整个流程就像单线程顺序一样
  • @sehe 我不认为这是一个骗局。您引用的问题与函数调用的顺序有关,但这个问题与内存访问的顺序有关。答案将取决于内存模型以及post() 是否具有隐式释放语义以及仿函数调用是否具有隐式获取语义。我的猜测是肯定的,但我不知道这是否在任何地方都有说明;它可能只是内部线程安全队列 @9​​87654331@ 包含的副作用。

标签: c++ concurrency boost-asio


【解决方案1】:

以下所有内容在内存排序上都有发生前的关系:io_service::post()、io_service::dispatch()、strand::post() 和 strand::dispatch()。这主要是io_service 和strand 的结果,它们有力地保证了单个对象可以同时使用。在这种不需要潜在阻塞同步的情况下,例如当发布到dispatch() 的处理程序可能在dispatch() 函数的上下文中执行时,就会发出full memory fence。

documentation 说明了使用内存屏障进行处理程序分配:

[...] 如果需要从不同线程调用分配函数,该实现将插入适当的内存屏障以确保正确的内存可见性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-26
    • 2019-01-22
    • 1970-01-01
    • 2020-12-25
    • 2020-08-09
    • 2012-05-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多