挥发性变量被优化? [英] volatile variable being optimized away?
问题描述
我有一个后台线程循环的状态变量 done
。当我想停止线程时,我将变量 done
设置为 true
。但显然这个变量从来没有设置。我理解编译器可能会优化它,所以我已标记完成
volatile
。但这似乎没有任何效果。注意,我不担心竞争条件,所以我没有使它 atomic
或使用任何同步结构。我如何让线程不跳过测试的变量在每次迭代?还是完全是其他问题? done
最初为 false
。
I have a background thread which loops on a state variable done
. When I want to stop the thread I set the variable done
to true
. But apparently this variable is never set. I understand that the compiler might optimize it away so I have marked done
volatile
. But that seems not to have any effect. Note, I am not worried about race conditions so I have not made it atomic
or used any synchronization constructs. How do I get the thread to not skip testing the variable at every iteration? Or is the problem something else entirely? done
is initially false
.
struct SomeObject
{
volatile bool done_;
void DoRun();
};
static void RunLoop(void* arg)
{
if (!arg)
return;
SomeObject* thiz = static_cast<SomeObject*>(arg);
while( !(thiz->done_) ) {
thiz->DoRun();
}
return;
}
推荐答案
volatile
在C ++中没有任何多线程的意义。它是C的延期,用作 sig_atomic_t
的修饰符,用于处理信号处理程序和访问内存映射设备。没有语言强制的强制C ++函数重新访问内存,这导致竞争条件(读者永远不会打扰检查两次作为优化),其他人上面注意到。
volatile
doesn't have any multi-threaded meaning in C++. It is a holdover from C, used as a modifier for sig_atomic_t
flags touched by signal handlers and for access to memory mapped devices. There is no language-mandated compulsion for a C++ function to re-access memory, which leads to the race condition (reader never bothering to check twice as an "optimization") that others note above.
使用 std :: atomic
(从C ++ 11或更高版本)。
Use std::atomic
(from C++11 or newer).
它可以,通常是无锁的:
It can be, and usually is lock-free:
struct SomeObject {
std::atomic_bool done_;
void DoRun();
bool IsDone() { return done_.load(); }
void KillMe() { done_.store(true); }
};
static void RunLoop(void *arg) {
SomeObject &t = static_cast<SomeObject &>(*arg);
cout << t.done_.is_lock_free(); // some archaic platforms may be false
while (!t.IsDone()) {
t.DoRun();
}
}
load / code>和
store()
方法强制编译器至少在每次迭代时检查内存位置。对于 x86 [_64]
, SomeObject
实例的 done _
成员将被本地缓存和检查,没有锁,甚至是原子/锁定的内存读取。如果你正在做一个比单向标志设置更复杂的事情,你需要考虑使用像显式记忆围栏等。
The load()
and store()
methods force the compiler to, at the least, check the memory location at every iteration. For x86[_64]
, the cache line for the SomeObject
instance's done_
member will be cached and checked locally with no lock or even atomic/locked memory reads as-is. If you were doing something more complicated than a one-way flag set, you'd need to consider using something like explicit memory fences, etc.
C ++ 11没有多线程内存模型,因此您必须依赖具有特殊编译器权限的第三方库(如pthreads)或使用特定于编译器的功能来获得等效的。
这篇关于挥发性变量被优化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!