问题描述
假设有两个线程分别运行 Thread1()
和 Thread2()
。线程1只是设置一个全局标志来告诉线程2退出,线程2定期检查是否应该退出。 volatile bool is_terminate = false;
void Thread1()
{
is_terminate = true;
}
void Thread2()
{
while(!is_terminate){
// ...
}
}
我想问上述代码是否安全,假设访问 is_terminate
是原子的。我已经知道许多材料状态, volatile
不能保证线程安全一般。但是在只共享一个原子变量的情况下,我们真的需要使用锁来保护共享变量吗?
这是可能排序的线程安全。
线程安全性往往取决于上下文。如果您从未从中读取 ,则更新bool总是线程安全。
如果你读它,那么答案取决于从读取的内容,以及读取的内容。
在某些CPU上,但不是全部,写入 bool
的对象将是原子的。 x86 CPU通常会使其原子,但其他人可能不。如果更新不是原子的,那么添加 volatile
将不会帮助你。
但下一个问题是重排序。编译器(和CPU)将按指定的顺序执行对 volatile
变量的读/写操作,而无需重新排序。这是很好的。
但不能保证重新排序一个 volatile
code> volatile 。所以一个常见的例子是,你定义了一些标志来保护对资源的访问,你使标志 volatile
,然后编译器将资源访问移动之前您检查标志。它允许这样做,因为它不是重新排序两个 volatile
访问的内部顺序,而只是一个 volatile
和非 - volatile
一个。
老实说,我会问的问题是:正确?
有可能 volatile
会在这种情况下工作,但为什么不保存自己的麻烦,并使它更清楚,这是正确的?相反,它围绕着一个内存屏障。
Assume there are two threads running Thread1()
and Thread2()
respectively. The thread 1 just sets a global flag to tell thread 2 to quit and thread 2 periodically checks if it should quit.
volatile bool is_terminate = false;
void Thread1()
{
is_terminate = true;
}
void Thread2()
{
while (!is_terminate) {
// ...
}
}
I want to ask if the above code is safe assuming that access to is_terminate
is atomic. I already know many materials state that volatile
can not insure thread-safety generally. But in the situation that only one atomic variable is shared, do we really need to protect the shared variable using a lock?
It is probably sort of thread-safe.
Thread safety tends to depend on context. Updating a bool is always thread safe, if you never read from it.And if you do read from it, then the answer depends on when you read from it, and what that read signifies.
On some CPUs, but not all, writes to an object of type bool
will be atomic. x86 CPUs will generally make it atomic, but others might not. If the update isn't atomic, then adding volatile
won't help you.
But the next problem is reordering. The compiler (and CPU) will carry out reads/writes to volatile
variables in the order specified, without any reordering. So that's good.
But it makes no guarantee about reordering one volatile
memory access relative to all the non-volatile
ones. So a common example is that you define some kind of flag to protect access to a resource, you make the flag volatile
, and then the compiler moves the resource access up so it happens before you check the flag. It's allowed to do that, because it's not reordering the internal ordering of two volatile
accesses, but merely a volatile
and a non-volatile
one.
Honestly, the question I'd ask is why not just do it properly?It is possible that volatile
will work in this situation, but why not save yourself the trouble, and make it clearer that it's correct? Slap a memory barrier around it instead.
这篇关于易失和多线程:是以下线程安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!