Multithreading 无锁线程之间的数据可见性

Multithreading 无锁线程之间的数据可见性,multithreading,c++11,synchronization,shared-memory,atomic,Multithreading,C++11,Synchronization,Shared Memory,Atomic,我了解C++11中内存排序的基本规则,尤其是发布-获取排序。我在两个线程之间共享了一大块内存,在这里我不需要原子性,但我希望最终确保一个线程所做的所有更改在另一个线程中可见,特别是在具有宽松内存模型的平台上 仅仅使用原子保护变量触发内存同步可以吗?例如: std::atomic<bool> guardVar; char *shared_mem=get_shared_mem(); (thread 1) while(true) { happens_many_things();

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

仅仅使用原子保护变量触发内存同步可以吗?例如:

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();
}
std::原子保护;
char*shared_mem=get_shared_mem();
(线程1)
while(true){
发生了很多事情;
用共享内存()做我想做的事;
guardVar.store(0,标准::内存\订单\发布);
}
(在线程2中)
while(true){
保证加载(标准::内存\u顺序\u获取);
如果不一致,则读取共享内存无问题();
}

再次,如果线程2在doSythEnvutixIyWANTION的中间读取“半准备就绪”状态不是问题,我只想确保在定义好的点之后得到线程1所写的所有更改。 基于此,它应该是有效的,但我在网上看不到类似的解决方案,而且如果它真的符合我的意图,也不容易测试

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

如果线程2在doSythEnvutiWiWangTyn的中间读取“准备就绪”状态,则不是问题。 这是一个错误,如果多个线程中有一个正在修改数据,则无法通过多个线程访问共享内存。C++标准称之为数据竞争,导致未定义行为。 两个线程之间的访问需要同步,但使用
std::atomic
的方式不正确。线程1中的
store\u 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 guardVar{false};
(线程1)
while(true){
while(guardVar.exchange(true,std::memory_order_acquire));//锁
发生了很多事情;
用共享内存()做我想做的事;
存储(false,std::memory\u order\u release);//解锁
}
(在线程2中)
while(true){
while(guardVar.exchange(true,std::memory_order_acquire));//锁
如果不一致,则读取共享内存无问题();
存储(false,std::memory\u order\u release);//解锁
}
但是,由于这是使用
std::atomic
作为互斥体的一种低效方式(注意旋转),因此您确实应该使用
std::mutex

更新:

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


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

Hmm。这确实是一种未定义的行为。Hmm。你是对的,根据标准,这确实是一种未定义的行为。假设我在模拟一个帧缓冲区,一个线程在随机访问中连续写入,另一个线程希望周期性地读取整个缓冲区来处理它。撕裂不是问题。我如何在两个线程都没有任何锁定的情况下解决这个问题?@ference这个场景确实是你问题的一部分。。我将更新应答器在我之前的评论中提到的帧缓冲区场景中,创建~1M个原子对象是不可行的,缓冲区中的每个字节对应一个。无论如何,我接受你的回答,因为你正确地回答了我原来的问题。也许我应该为这个具体的帧缓冲区案例重新措辞并提出一个新问题。为了警告关注者,我发现了数据竞争。现在我看到了两种可能的解决方案:1)在汇编中编写读取线程,并在第一个循环中保持release-store语义以强制执行内存限制指令,或2)将帧缓冲区声明为易失性数组,从而防止编译器优化引用文章中描述的这些讨厌的事情。这两个选项都不符合标准,但我无法想象编译器会如何欺骗我。:)