我知道我应该使用volatile
关键字来告诉编译器不要优化内存读写变量。我也知道在大多数情况下它应该只用于与 non-C++ memory 对话。
但是,我想知道volatile
在持有指向某个局部(堆栈)变量的指针时是否必须使用。
例如:
//global or member variable
/* volatile? */bool* p_stop;
void worker()
{
/* volatile? */ bool stop = false;
p_stop = &stop;
while(!stop)
{
//Do some work
//No usage of "stop" or p_stop" here
}
}
void stop_worker()
{
*p_stop = true;
}
在我看来,具有某种优化级别的编译器可能会看到它stop
是一个局部变量,它永远不会改变,并且可以while(!stop)
用 a替换,while(true)
从而改变*p_stop
而什么也不做。
那么,在这种情况下是否需要将指针标记为 volatile 呢?
PS:请不要教我为什么不使用它,使用这个 hack 的真实代码是出于(复杂到解释的)原因这样做的。
编辑:
我没有提到这两个函数在不同的线程上运行。这worker()
是第一个线程的函数,应该使用p_stop
指针从另一个线程停止。
我不想知道有什么更好的方法可以解决这种 hack 背后的真正原因。我只是想知道这是否是 C++ 中的定义\未定义行为(11),以及这是否依赖于编译器\平台\等。到目前为止,我看到@Puppy 说每个人都错了,这是错的,但没有引用表示这一点的特定标准。
我知道你们中的一些人对“不要教我”部分感到冒犯,但请坚持真正的问题 - 我应该使用volatile
还是不使用?或者这是UB?如果可以的话,请通过提供完整的答案来帮助我(和其他人)学习新东西。
我只是想知道这是否是 C++ 中的定义\未定义行为(11)
Ta-da(来自N3337,“准 C++11”)
如果其中一个修改了内存位置 [..] 而另一个访问或修改了相同的内存位置,则两个表达式计算会发生冲突。
§1.10/4
和:
如果一个程序在不同的线程中包含两个相互冲突的动作,那么它的执行就包含数据竞争,其中至少一个不是原子的,并且都不在另一个之前发生。任何此类数据竞争都会导致未定义的行为。[..]
§1.10/21
您正在stop
从不同的线程访问(的内存位置)对象,这两种访问都不是原子的,因此也没有“发生在之前”的关系。简而言之,您有数据竞争,因此存在未定义的行为。
我不想知道有什么更好的方法可以解决这种 hack 背后的真正原因。
原子操作(由 C++ 标准定义)是(可靠地)解决这个问题的唯一方法。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句