【问题标题】:Is std::memory_order_relaxed enough for checking "Availability"?std::memory_order_relaxed 是否足以检查“可用性”?
【发布时间】:2016-01-23 10:45:20
【问题描述】:

我有一个并发对象,它可能或可能每次都保存指向函数的指针。对象的架构如下所示:

struct ConcurrentObject{
  //variables
  std::atomic<void(*)()> callback;
} 

所以一个线程可能决定他想用这个对象附加回调并将它转发:

ConcurrentObject* co = new ConcurrentObject(); //I'm using smart pointers, no worries.
//do some logic
co->callback = someCallback; //void(*)() , this may be difference callback every time

我在修改后得到这个对象并检查回调是否可用:

auto co = aquireConcurrentObject();
auto callback = co->callback.load();
if (callback){
    callback()
}

现在,我们知道在不指定任何内存顺序的情况下,默认传递的内存顺序是memory_order_seq_cst,它告诉编译器(简而言之)“不要乱序读取或写入指令以使程序更快,保持相对顺序代码指定的指令,并使其通过 cpu 可见。

我们也知道它是一个很好的性能障碍,因为编译器可以执行的操作受到更多限制。

我的问题是 - std::memory_order_relaxed 是否足以执行此操作?

【问题讨论】:

    标签: c++ multithreading c++11 thread-safety memory-barriers


    【解决方案1】:

    是的,您是正确的,在您的示例中 std::memory_order_relaxed 可以安全使用,因为您的代码仅依赖于回调是原子的事实。您的代码不受可能的内存操作重新排序的影响

    【讨论】:

      【解决方案2】:

      回调指针访问的内存顺序会影响回调使用的变量的“可见性”。

      如果你的回调:

      1) 类似于 constexpr,即它不使用任何东西,除了它的参数和常量全局变量,或者

      2) 仅使用变量,这些变量在可能使用回调之前初始化 (happens-before),

      然后使用std::memory_order_relaxed 既可以存储也可以加载。

      但是如果您在//do some logic 下的代码初始化了一些变量,供回调使用,那么您应该至少使用std::memory_order_release/std::memory_order_acquire 进行相应的存储和加载。否则,回调的执行可能会看到这些变量未初始化(更严格地说,这将是 C++11 标准意义上的数据竞争,即未定义的行为)。

      【讨论】:

        【解决方案3】:

        您有衡量性能影响的方法吗?在这里更改内存顺序可能看起来像一个良好的性能启动(这似乎是有效的),但实际上,在大多数应用程序中 - 这并不重要。

        在此处更改内存模型意味着维护此代码的任何人都需要格外小心,以免破坏它,因此这是您在执行此类操作时要承担的另一个风险。

        此类优化需要详细记录并在被证明是性能瓶颈后选择。非必要不要乱搞。

        【讨论】:

        • 这更适合作为评论,因为您没有明确回答问题。无论如何,它可能不是瓶颈,但它通常会降低性能,您可以使用和不使用 std::memory_order_relaxed 来测量程序以查看受影响的程度。我的问题是我什至可以这样做以分析正确的程序而不是错误的程序。
        猜你喜欢
        • 1970-01-01
        • 2021-05-09
        • 2011-09-11
        • 1970-01-01
        • 2013-04-14
        • 2021-01-26
        • 2018-03-06
        • 1970-01-01
        • 2015-02-17
        相关资源
        最近更新 更多