从我从Herb Sutter和其他人那里读到的内容来看volatile
,至少在C / C ++方面,您会认为并发编程是完全正交的概念。
但是,在GCC实现中,所有std::atomic
的成员函数都具有volatile
限定符。在Anthony Williams的实现中也是如此std::atomic
。
那怎么办,我的atomic<>
变量是否需要volatile
?
从我从Herb Sutter和其他人那里读到的内容来看volatile
,至少在C / C ++方面,您会认为并发编程是完全正交的概念。
但是,在GCC实现中,所有std::atomic
的成员函数都具有volatile
限定符。在Anthony Williams的实现中也是如此std::atomic
。
那怎么办,我的atomic<>
变量是否需要volatile
?
volatile
在单个线程中进行读取和写入的保证是按顺序完成的,并且易失性对象不能在其上调用任何非易失性成员函数(就像const)。但除此之外,我对C ++中的线程一无所知。每次我尝试在标准中读到它,我开始放弃,不能够把握文本的xD间接性和逻辑的绝对数量
Answers:
为什么volatile
贯穿始终使用限定词std::atomic
?
这样挥发性对象也可以是原子的。看到这里:
相关报价是
定义功能和操作以使用易失性对象,因此应该易失的变量也可以是原子的。但是,原子性不需要挥发性限定符。
我的atomic<>
变量是否需要volatile
?
不,原子对象不必是易失的。
volatile
操作仅在wrt中进行。其他volatile
访问。 atomic<T>
释放,获取和seq_cst操作按顺序排序。普通的非原子变量,所以用滚动自己原子能只是 volatile
不能给你同样的ACQ /相对语义没有障碍。 当编译器利用as-if规则来优化原子时,例如,防止将“冗余”写入合并到进度计数器中,volatile atomic<T>
可能将来会有用。
volatile sig_atomic_t
,它在技术上仍然是UB ,但是大多数实际的实现int
对于加载/存储来说自然是原子的(定义行为)。(我最近对此写了一个很大的答案:MCU编程-C ++ O2优化在循环时中断)仍然,如果您需要任何订购wrt。非原子变量(例如,中断处理程序编写一个普通缓冲区然后设置一个原子标志),则可以使用宽松的原子加载,并且可以atomic_signal_fence(memory_order_acquire)
在主代码中防止编译时重新排序。
volatile
在真正的编译器上会发生什么。但是您可以安全地进行信号或中断处理程序之间的交互的操作集非常有限,并且对于太宽的类型(自然而然是原子的)没有帮助。但是只要您坚持这一点,就可以。正如我在上一条评论的链接中所显示的那样,您可以使用C ++ 11轻松原子signal_fence
来volatile
完全有效地完成该用例的所有工作,并可以选择使用释放/获取排序signalf_fence
。
总结其他人正确编写的内容:
C / C ++volatile
用于硬件访问和中断。C ++ 11atomic<>
用于线程间通信(例如,采用无锁代码)。这两个概念/用途是正交的,但是它们有重叠的要求,这就是为什么人们经常将二者混淆。
其原因atomic<>
有volatile限定的功能是它具有const限定的功能,同样的原因,因为它可能在原则上的对象既atomic<>
和也const
和/或volatile
。
当然,正如我的文章所指出的,另一个令人困惑的原因是C / C ++volatile
与C#/ Java不同volatile
(后者基本上等效于C ++ 11 atomic<>
)。
volatile
标志在线程不安全的代码上产生编译时错误(使用volatile
实例来锁定接口的使用并const_cast
删除volatile)。获取互斥体时)。难道意义添加一个类型限定符“线程”或类似的用于此目的的语言(我只是想大声)的文章是在这里:drdobbs.com/cpp/...
作为常量,volatile是可传递的。如果将方法声明为,volatile
则无法对其调用任何非易失性方法或其成员属性。通过使用std::atomic
方法,volatile
您可以允许volatile
包含以下内容的类中的成员方法进行调用:std::atomic
变量的。
我今天过得不好...太混乱了...也许举个例子可以帮助:
struct element {
void op1() volatile;
void op2();
};
struct container {
void foo() volatile {
e.op1(); // correct
//e.op2(); // compile time error
}
element e;
};