2017-06-07 26 views
2

我寫了一個非常簡單的代碼來重現我的問題。C++變量不會改變,直到線程完成

#include <iostream> 
#include "tools.h" //contains s_sleep() 
#include <thread> 
using namespace std; 

void change(int *i) 
{ 
     while (true) 
     { 
       *i = 4356; 
     } 
} 

int main() 
{ 
     int v=3; 
     cout << v <<endl; 
     thread t(change, &v); 
     s_sleep(1); //sleep one second 
     cout << v << endl; 
     t.join(); 
} 

輸出爲3,再次爲3後。但是,當我改變一個行

//while (true) 

我收到3,一秒鐘後4356.

怎麼可能? 希望有人能幫助。

+10

請閱讀有關數據競賽的內容。你的程序因爲它而產生未定義的行爲。 – nwp

回答

2

請指定您正在使用的編譯器。我使用的是Microsoft Visual C++編譯器,在我的視覺工作室中,我看到兩次都輸出了3,然後是4356.

這是我在計算機上運行的代碼。

#include <ctime> 
#include <thread> 
#include <iostream> 
using namespace std; 
void change(int *i) { 
    while (true) { // commented out this later, the result is same. 
     *i = 4356; 
    } 
} 

int main() { 
clock_t tstart = clock(); 
    int v = 3; 
    cout << v << endl; 
    thread t(change, &v); 
    while(double(clock() - tstart)/CLOCKS_PER_SEC < 3.0) { // Instead of your s_sleep 
     int x = 1; // Just a dummy instruction 
    } 
    cout << v << endl; 
    t.join(); 
    return 0; 
} 

對我的結果的解釋是線程「t」不知道變量「v」的任何內容。它只是得到一個int類型的指針,它將指針位置的值直接編輯到內存中。因此,當主(第一個)線程 再次訪問變量「v」時,它只讀取分配給「v」的內存並打印它獲取的內容。

而且,「tools.h」中的代碼是什麼?它與變量「v」有什麼關係。

如果沒有,那麼它必須是編譯器方差(您的編譯器可能與我的不同,也許gcc或g ++?)。這意味着,您的編譯器必須緩存(或類似的東西)變量才能更快地訪問。就像在當前線程中一樣,變量沒有被改變,只要它被訪問,編譯器就會給出變量的舊值(編譯器認爲這個值不變)。 (我對此不太確定)

+0

正如問題的評論中所說:程序具有未定義的行爲,所以如果它適用於您的編譯器沒有多大意義,那麼在編譯不同的配置時甚至可能會有所不同。存在CPU擁塞和緩存以及其他涉及從不同線程訪問數據時可能導致不同結果的事情。總是使用'std :: atomic'或者用'std :: mutex'保護這個;他們可能會比較慢,但他們保證寫在一個線程中的內容會反映在另一個線程中。 – stefaanv

+0

您是對的。最簡單的解釋是,程序具有未定義的行爲,因爲有時第二個線程中的代碼比第一個線程早運行,有時反之亦然。 (因爲兩者相互平行) –

+0

你說得對。我使用的是GNU編譯器套件,問題在於優化。我禁用了它,現在它工作了!謝謝! – JuliB

-1

這也可能是由於緩存。您首先讀取一個線程的變量,然後從另一個線程處理該變量並從第一個線程再次讀取該變量。編譯器無法知道它在此期間發生了變化。 要安全地做到這一點,「v」必須被宣佈爲易失性

+3

如果你可以使用C++ 11,應該使用線程通信'std :: atomic',而不是'volatile' – stefaanv

+0

...我認爲volatile會很好地解釋這裏發生的事情。作者只問「這怎麼可能」 – Tobi

+0

我們在2017年中,所以除了一些深度嵌入式系統外,C++ 11應該被視爲C++。 「爲了安全地做到這一點'v'必須被聲明爲volatile'意味着你建議使用volatile。易失性問題在於它有時可行,但在多核系統上可能會失敗。這是一個編譯器功能,但CPU /緩存對此一無所知,另請參閱https://stackoverflow.com/a/2485177/104774。唉,接受的答案(其他編譯器/不優化)更糟糕。 – stefaanv