线程之间没有锁定的数据可见性

时间:2017-04-03 22:05:14

标签: multithreading c++11 synchronization shared-memory atomic

我理解C ++ 11中内存排序的基本规则,尤其是发布 - 获取顺序。我在两个线程之间共享了一大块内存,我不需要原子性,但是要确保最终线程完成的所有更改在另一个线程中都可见,尤其是在具有宽松内存模型的平台上。

仅仅使用原子保护var来触发内存同步是否可以?如,

std::atomic<bool> guardVar;
char *shared_mem=get_shared_mem();

(thread 1)
while(true) {
  happens_many_things();
  do_whatever_I_want_with_shared_mem();
  guardVar.store(0, std::memory_order_release);
}

(in thread 2)
while(true) {
  guardVar.load(std::memory_order_acquire);
  read_shared_mem_no_problem_if_inconsistent();
}

同样,如果线程2读取&#34;半就绪&#34;那么这不是问题。在do_whatever_I_want_with_shared_mem()中间的状态,我只想确保在一个明确定义的点之后得到线程1写的所有更改。

基于this article它应该可以工作,但是我没有在网上看到这样的解决方案,如果它真的符合我的意图就不容易测试。

可以吗?如果是,是否有更优雅的方式?

1 个答案:

答案 0 :(得分:1)

  

如果线程2读取&#34;半就绪&#34;这不是问题。在do_whatever_I_want_with_shared_mem()

中间的状态

这是一个错误,如果其中一个线程正在修改数据,则无法通过多个线程访问共享内存。 C ++标准将其称为数据竞争,它会导致未定义的行为。

两个线程之间的访问需要同步,但使用std::atomic的方式不正确。线程1中的store_release紧接着再次访问相同的数据。 load_acquire相同;两个操作之间没有同步,因此您正在处理数据竞争。

为了确保您的共享内存一次只能由一个线程访问,guardVar在技术上可以像这样使用:

std::atomic<bool> guardVar{false};

(thread 1)
while(true) {

    while (guardVar.exchange(true, std::memory_order_acquire));  // LOCK

    happens_many_things();
    do_whatever_I_want_with_shared_mem();

    guardVar.store(false, std::memory_order_release);  // UNLOCK
}

(in thread 2)
while(true) {

    while (guardVar.exchange(true, std::memory_order_acquire)); // LOCK

    read_shared_mem_no_problem_if_inconsistent();

    guardVar.store(false, std::memory_order_release);  // UNLOCK
}

但由于这是以相当低效的方式使用std::atomic作为互斥锁(注意旋转),你真的应该使用std::mutex

<强>更新

仍然可以在没有锁定的情况下使用共享内存,但是您有责任确保在共享内存中访问的每个单独对象都是无数据竞争(std::atomic对象限定)。

然后你或多或少地得到你在问题中描述的行为,其中第二个线程可能会看到&#34;半就绪&#34; state(某些对象已更新,其他对象未更新)。没有同步,第二个线程无法真正知道第一个线程的更新何时完成,但至少可以安全地同时读取/写入数据竞争对象。

相关问题