假设有运行两个线程Thread1(),并Thread2()分别.线程1只设置一个全局标志来告诉线程2退出,线程2定期检查它是否应该退出.
volatile bool is_terminate = false;
void Thread1()
{
is_terminate = true;
}
void Thread2()
{
while (!is_terminate) {
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
我想问上面的代码是否安全,假设访问is_terminate是原子的.我已经知道许多材料状态,volatile一般不能确保线程安全.但是在只共享一个原子变量的情况下,我们真的需要使用锁来保护共享变量吗?
我的理解是,如果两个线程从同一块内存中读取,并且没有线程正在写入该内存,那么操作是安全的.但是,我不确定如果一个线程正在读取而另一个正在写入会发生什么.会发生什么?结果是否未定义?或者阅读是否陈旧?如果陈旧的读取不是一个问题,是否可以对变量进行非同步读写?或者数据是否可能被破坏,读取和写入都不正确,在这种情况下应该始终同步?
我想说我已经知道这是后一种情况,内存访问的竞争使状态未定义......但我不记得我在哪里学到了这些并且我很难找到在谷歌上回答.我的直觉是变量在寄存器中操作,并且真实(如在硬件中)并发是不可能的(或者是它),因此可能发生的最坏情况是陈旧数据,即以下内容:
WriteThread: copy value from memory to register
WriteThread: update value in register
ReadThread: copy value of memory to register
WriteThread: write new value to memory
Run Code Online (Sandbox Code Playgroud)
此时读取线程具有陈旧数据.
自从我开始使用多线程以来,我一直在问自己这个问题:
是否从不同线程写入和读取变量未定义行为?
让我们使用最小的例子,我们在一个线程中增加一个整数并读取另一个线程中的整数。
void thread1()
{
x++;
}
void thread2()
{
if (x == 5)
{
//doSomething
}
}
Run Code Online (Sandbox Code Playgroud)
我知道加法操作不是原子的,因此我可以在第一个线程处于加法操作中间时从第二个线程读取,但有些事情我不太确定。
不会x让他的价值,直到整个加法操作完成,然后被分配这个新的价值,还是x有一个中间状态,其中从中读取会导致不确定的行为。
如果第一个理论适用,那么x在写入时读取将简单地在添加之前返回值并且不会有那么大的问题。
如果第二个理论是正确的,有人可以更详细地解释加法运算的过程是什么以及为什么它会是未定义的行为(也许举个例子?)
谢谢
阅读有关取消和pthreads的信息,在我看来,无限循环的线程的最佳实践不是取消线程而是创建将由线程检查的标志.
这种情况意味着在某些时候,某个线程可能会在有人写入该标志时尝试读取该标志.这个线程安全吗?我如何安全地同时使用get_flag()和set_flag()?