Closed. This question is off-topic。它当前不接受答案。
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            想改善这个问题吗? Update the question,所以它是on-topic,用于堆栈溢出。
                        
                        5年前关闭。
                                                                                            
                
        
我对此问题感到困惑,当我查看某人的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通话时间times1Func2通话时间times2


times1 - times2总是= g_var吗?
如果代码在C中而不在C++中怎么办?
如果g_var使用volatile装饰怎么办?
使用atomic_increase / atomic_decrease是唯一正确的方法吗?


我认为,它应该在violatile中使用C++,而不必在Windows中像InterlockedIncrement那样使用原子操作,因为汇编代码只是一行,一条add指令:

mov         eax,1
add         dword ptr [a],eax

最佳答案

按照出现的顺序回答您的问题:


不,您的程序具有未定义的行为。可能是这样的情况:线程1读取变量(要增加),被中断,然后线程2读取变量(要减少),将其减小并写回(因此与我们开始的值相比减一)然后,线程1继续,增加其记忆的旧值并将其写回到变量中,与我们开始使用的值相比,结果加一。
语言在这里没有任何改变。
volatile仅保证单个线程可能不会缓存变量的值,即++g_var; ++g_var;将读取变量,增加,写入,读取,增加,写入。优化程序不会将其替换为g_var += 2。但是线程仍然可以在读写之间中断,这是很危险的部分。
这是您需要原子操作的完美示例。在int上使用原子操作,或者使用std::atomic<int>包装器,该包装器在调用常规运算符时自动为您执行此操作,从而使您的代码更具可读性。

只需将int g_var替换为std::atomic<int> g_var即可解决任何问题。

10-07 13:06
查看更多