C++ 一个有两个线程的程序,一个线程增加全局变量,另一个线程减少相同的变量,变量总是正确的吗?
我对这个问题感到困惑,它只是在我查看某人的C++ 一个有两个线程的程序,一个线程增加全局变量,另一个线程减少相同的变量,变量总是正确的吗?,c++,c,multithreading,locking,C++,C,Multithreading,Locking,我对这个问题感到困惑,它只是在我查看某人的C++代码时出现的 例如,在C++中: // Global var int g_var = 0; // thread 1 call Func1() forever: void Func1() { ++g_var; } // thread 2 call Func2() forever: void Func2() { --g_var; } 定义Func1调用时间times1,Func2调用时间times2 times1-times2是否总是=
C++
代码时出现的
例如,在C++中:
// Global var
int g_var = 0;
// thread 1 call Func1() forever:
void Func1() {
++g_var;
}
// thread 2 call Func2() forever:
void Func2() {
--g_var;
}
定义Func1
调用时间times1
,Func2
调用时间times2
是否总是times1-times2
=g_var
- 如果代码在
中,而不是在C
中,该怎么办C++
- 如果
使用g_var
装饰怎么办volatile
- 使用原子增加/原子减少是唯一正确的方法吗
C++
中使用violatile
,而不是像Windows中的InterlockedIncrement
那样使用原子操作,因为汇编代码只是一行,一个add
指令:
mov eax,1
add dword ptr [a],eax
按照问题出现的顺序回答问题:
- 否,您的程序具有未定义的行为。可能是这样的情况:线程1读取变量(要增加),被中断,然后线程2读取变量(要减少),减少变量并将其写回(因此与我们开始的值相比它是负一),然后线程1继续,增加其记忆的旧值并将其写回变量,与我们开始时的值相比,结果为正1
- 这里的语言没有任何变化
仅保证单个线程可能不会缓存变量的值,即volatile
++g_var++g_var代码>将读取变量,递增,写入,读取,递增,写入。优化器不会将其替换为
。但是,阅读和写作之间的线索仍然会被打断,这是危险的部分g_var+=2
- 这是一个需要原子操作的完美例子。在
上使用原子操作,或者使用int
包装器,当您调用普通运算符时,该包装器会自动为您执行此操作,使代码更具可读性 只需将std::atomic
替换为int g_var
即可解决任何问题std::atomic g_var
- 不,因为代码不是线程安全的
没有帮助,它阻止在寄存器或其他优化中“缓存”值,但不会使操作原子化volatile
- 对。或者,如果您可以选择使用锁定机制自己实现这些功能,则不需要
int g_var=0代码>应该是。为一个特定平台生成的汇编指令的可能重复并不重要。有些处理器需要单独的指令来读取和写入值。即使是一条指令也不一定意味着它是原子指令!请注意,不显式使用原子操作仍可能编译为原子的汇编指令(即,标准并不禁止它!)。但除非你明确使用原子学,否则你不能保证它能做到这一点。更糟糕的是:调试会很困难,因为您可能认为它可以工作,但这只是您在这台特定机器上的运气,但当移植到不同的体系结构时,它可能会崩溃!对于未定义的行为,通常是这样的:它可能在一个设置中工作,但不能保证在其他设置中工作。非常令人沮丧。violatile
描述得非常形象;)。。。