【问题标题】:`volatile` to sync variable between threads`volatile` 在线程之间同步变量
【发布时间】:2013-08-10 16:51:39
【问题描述】:

我有一个变量int foo,可以从两个线程访问。假设我没有竞争条件问题(访问受互斥锁保护,所有操作都是原子的,或者任何其他保护竞争条件的方法),仍然存在“寄存器缓存”问题(因为没有更好的名称) ,其中编译器可能会假设如果变量被读取两次而没有在其间写入,则它是相同的值,因此可能会“优化”掉以下内容:

while(foo) { // <-may be optimized to if(foo) while(1)
  do-something-that-doesn't-involve-foo;
}

或

if(foo) // becomes something like (my assembly is very rusty): mov ebx, [foo]; cmp ebx, 0; jz label;
  do-something-that-doesn't-involve-foo;
do-something-else-that-doesn't-involve-foo;
if(foo) // <-may be optimized to jz label2;
  do-something;

将foo 标记为volatile 是否可以解决此问题?是否保证来自一个线程的更改会到达另一个线程?

如果没有,还有什么其他方法可以做到这一点?我需要 Linux/Windows 的解决方案(可能是单独的解决方案),没有 C++11。

【问题讨论】:

  • 我记得看到标准中的一句话说你不应该再在线程中使用 volatile,在 c++ 中,我会尝试找到它
  • 这里的问题是“假设我没有竞争条件问题”。这是一个巨大的假设。
  • std::atomic&lt;int&gt; 不做你想做的事吗?
  • 我一直使用 volatile 来确保没有完成“寄存器缓存”,并且它始终有效。

标签: c++ c multithreading volatile


【解决方案1】:

您需要的是内存屏障。

MemoryBarrier();

或

__sync_synchronize();

编辑:我已将有趣的部分加粗,这是 wiki 文章 (http://en.wikipedia.org/wiki/Memory_barrier#cite_note-1) 和相关参考 (http://www.rdrop.com/users/paulmck/scalability/paper/whymb.2010.07.23a.pdf) 的链接

这是您其他问题的答案(来自维基百科): 在 C 和 C++ 中,volatile 关键字旨在允许 C 和 C++ 程序直接访问内存映射 I/O。内存映射 I/O 通常要求源代码中指定的读取和写入以指定的确切顺序发生,不得遗漏。编译器对读取和写入的遗漏或重新排序会破坏程序与内存映射 I/O 访问的设备之间的通信。 C 或 C++ 编译器不能对易失性内存位置的读取和写入重新排序,也不能省略对易失性内存位置的读取或写入。 关键字 volatile 不能保证内存屏障来强制缓存一致性。因此,仅使用“volatile”不足以在所有系统和处理器上使用变量进行线程间通信[1]

看看这个,它对这个主题提供了很好的解释: http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-1-of-2 http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-2-of-2

【讨论】:

    【解决方案2】:

    如果访问受到互斥锁的保护,则无需担心任何问题。 volatile 关键字在这里没用。互斥锁是一个完整的内存屏障,因此其地址在外部可见的任何对象都不能通过互斥锁锁或解锁调用进行缓存。

    【讨论】:

    • 是的。 Mutex 负责缓存一致性。
    • 为了清楚起见:缓存我指的不仅仅是机器级缓存,还包括编译器在寄存器中的值缓存。
    【解决方案3】:

    最初引入volatile 关键字是为了表示该值可以由硬件更改。当硬件设备具有内存映射寄存器或内存缓冲区时,就会发生这种情况。正确的做法是仅将其用于此目的。

    所有现代同步语言结构和同步库都没有使用这个关键字。应用程序级程序员应该做同样的事情。

    【讨论】:

      猜你喜欢
      • 2019-05-06
      • 2016-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多