在C/C++中,volatile变量是否保证最终在线程之间具有一致的语义?

Jac*_*oyd 10 c c++ multithreading portability memory-model

任何通常遵循的标准(ISO C或C++,或任何POSIX/SUS规范)是否有任何保证,由多个线程访问的变量(可能标记为volatile)(未被互斥锁保护)将最终保持一致如果分配给?

要提供一个特定示例,请考虑共享变量v的两个线程,初始值为零.

线程1:v = 1

线程2:while(v == 0)yield();

线程2是否保证最终终止?或者它可以想象永远旋转,因为缓存一致性从未启动并使得赋值在线程2的缓存中可见?

我知道C和C++标准(在C++ 0x之前)完全没有关于线程或并发的说法.但我很好奇,如果C++ 0x内存模型,或pthreads,或其他任何东西,保证这一点.(显然这确实可以在Windows上运行32位x86;我想知道它是否可以依赖于某些东西,或者它是否恰好在那里工作).

moo*_*dow 12

这将取决于您的架构.虽然要求显式缓存刷新或内存同步以确保其他线程可以看到内存写入是不常见的,但没有什么可以排除它,我当然遇到了平台(包括我目前正在开发的基于PowerPC的设备),其中显式指令必须执行以确保刷新状态.

请注意,线程同步原语(如互斥锁)将根据需要执行必要的工作,但如果只需要确保状态可见而不关心一致性,通常不需要线程同步原语 - 只需同步/刷新指令满足.

编辑:现在还有人在有关confustion volatile关键字- volatile确保编译器不会生成代码,明确缓存在寄存器中的数据,但这是不是同样的事情,处理与透明缓存/重新排序的读取和写入硬件.阅读如这个多布斯博士的文章,或回答这个 SO问题,还是只挑选自己喜欢的编译器,针对一个弱一致性内存架构样细胞,编写一些测试代码,并比较一下编译器生成对你" d需要为了确保写入对其他进程可见.

  • @David:这是错的."访问`volatile`对象必须严格按照语言标准定义的抽象机进行评估." 这是关于C++可能执行什么样的优化的声明,而不是程序员为处理架构怪癖可能希望做的额外处理.它说编译器必须为源中的每个赋值生成一个显式写入指令,但它没有说明生成`flush`或`sync`或`eieio`或者你的CPU可能需要实际导致数据命中的任何内容按程序顺序或根本不记忆. (13认同)
  • @MSalters:你的结论再次是错误的.对挥发性物质的读取和写入是可观察到的副作用:同样,这是关于编译器可能不执行的优化类型的声明,而不是关于它必须生成的其他代码的声明.编译器可能不会生成缓存易失性数据的代码,但是它被告知存储的硬件缓存数据不是编译器的责任. (5认同)
  • @MSalters:你夸大了编译器的责任。由程序员而不是编译器来选择处理硬件并发问题的最合适的方法。“易失性”是告诉编译器不要重新排序写入的一种方式,这样您就不会与编译器发生冲突。这种责任分离有一个很好的理由:像 Cell 这样的架构包含多个同步/栅栏/屏障指令,其成本和效果截然不同,并且编译器无法知道哪一个最适合给定情况。 (2认同)

APr*_*mer 5

如果我已经正确理解了相关部分,C++ 0X将不能保证它对于独立变量甚至是volatile变量(volatile不是为那个用途而设计的),而是会引入原子类型,你将获得保证(见标题<atomic>).