2016-11-22 46 views
-1

我的代碼中存在一個錯誤,我已經確定這是一個競爭條件。我知道這是一種競賽狀況,因爲它會間歇性地發生。我已經研究瞭如何防止這些比賽條件,我碰到這個如何使用鎖來防止競爭條件

 for (int i = 0; i < 10000000; i++) 
     { 
      //lock x 
      x = x + 1; 
      //unlock x 
     } 

可能有人請再詳細我如何可以實現這些鎖?

+4

如果你正在使用'pthread's,那麼你可以使用'pthread_mutex_lock'和'pthread_mutex_unlock' –

+1

最簡單的方法,如果你有C++ 11,就是'std :: atomic x;'。 –

回答

2

我知道這是一個競爭條件,因爲它雖然比賽條件一般都出現間歇性出現間歇

,還有其他類型的具有類似行爲的錯誤,讓你的推理是不能保證準確。也就是說,在沒有看到程序的情況下,確定這是多線程程序中的一個非常可能的問題。

請問有人可以進一步瞭解我如何實現這些鎖嗎?

互斥鎖無法在C++中實現。它們通常使用機器指令Test-and-set來實施。

但是,您不需要自己實現鎖定。自從C++ 11以來,標準庫已經包含了一個實現。更好的是,它包含更高級別的原子類型(std::atomic),它提供原子訪問而不顯式鎖定執行(原子類型的實現甚至可以使用更有效的指令來避免鎖定,具體取決於目標架構)。

如果您的標準庫已過時,那麼您可以使用操作系統提供的線程API。它幾乎肯定爲您提供某種互斥體結構。

4

你的例子表明,你想要在你的線程中執行的所有操作都是對int變量的操作。如果真的如此,正如其他人指出的那樣,std::atomic可能是實現它的最簡單方法。

#include <thread> 
#include <atomic> 
#include <iostream> 

std::atomic<int> x = 0; 

void increment() 
{ 
    for(int i = 0; i < 10000000; ++i) 
    { 
     ++x; 
    } 
} 

int main() 
{ 
    std::thread t1(increment); 
    std::thread t2(increment); 

    t1.join(); 
    t2.join(); 

    std::cout << x; 
} 

但是,爲了保護更復雜的操作從多個線程同時執行,你應該使用std::lock_guard。它使用RAII(資源獲取是初始化)原則在其生命週期中鎖定互斥鎖。

#include <thread> 
#include <mutex> 
#include <iostream> 

int x = 0; 
std::mutex mtx; 

void increment() 
{ 
    for (int i = 0; i < 10000000; i++) 
    { 
     std::lock_guard<std::mutex> lock(mtx); //lock mtx 
     ++x; 

     // mtx is automatically released when lock 
     // goes out of scope -> RAII 
    } 
} 

int main() 
{ 
    std::thread t1(increment); 
    std::thread t2(increment); 

    t1.join(); 
    t2.join(); 

    std::cout << x; 
} 

編輯

基於這裏您的意見是另一個例子:

#include <thread> 
#include <mutex> 
#include <iostream> 

class Foo 
{ 
public: 
    void increment() 
    { 
     for (int i = 0; i < 10000000; ++i) 
     { 
      std::lock_guard<std::mutex> lock(mtx); //lock mtx 
      ++x; 

      // mtx is automatically released when lock 
      // goes out of scope -> RAII 
     } 
    } 

    void decrement() 
    { 
     for (int i = 0; i < 10000000; ++i) 
     { 
      std::lock_guard<std::mutex> lock(mtx); //lock mtx 
      --x; 

      // mtx is automatically released when lock 
      // goes out of scope -> RAII 
     } 
    } 

    static int x; 
    static std::mutex mtx; 
}; 

int Foo::x = 0; 
std::mutex Foo::mtx; 

int main() 
{ 
    std::thread t1(&Foo::increment, Foo()); 
    std::thread t2(&Foo::decrement, Foo()); 

    t1.join(); 
    t2.join(); 

    std::cout << Foo::x; 
} 
+0

如果變量在對象成員函數中,我仍可以實現此代碼嗎? – MagnusHimmler

+0

不知道我是否正確理解你。也許你可以用一個小例子編輯你的問題?但是,如果你的變量是某個成員函數中的局部變量,那麼我很難懷疑你的問題是關於這個變量的競爭條件。 – sigy

+0

我有一個靜態變量,由同一個對象內的兩個不同的函數訪問。但有時第二個函數完全跳過這個變量 – MagnusHimmler