我的代碼中存在一個錯誤,我已經確定這是一個競爭條件。我知道這是一種競賽狀況,因爲它會間歇性地發生。我已經研究瞭如何防止這些比賽條件,我碰到這個如何使用鎖來防止競爭條件
for (int i = 0; i < 10000000; i++)
{
//lock x
x = x + 1;
//unlock x
}
可能有人請再詳細我如何可以實現這些鎖?
我的代碼中存在一個錯誤,我已經確定這是一個競爭條件。我知道這是一種競賽狀況,因爲它會間歇性地發生。我已經研究瞭如何防止這些比賽條件,我碰到這個如何使用鎖來防止競爭條件
for (int i = 0; i < 10000000; i++)
{
//lock x
x = x + 1;
//unlock x
}
可能有人請再詳細我如何可以實現這些鎖?
我知道這是一個競爭條件,因爲它雖然比賽條件一般都出現間歇性出現間歇
,還有其他類型的具有類似行爲的錯誤,讓你的推理是不能保證準確。也就是說,在沒有看到程序的情況下,確定這是多線程程序中的一個非常可能的問題。
請問有人可以進一步瞭解我如何實現這些鎖嗎?
互斥鎖無法在C++中實現。它們通常使用機器指令Test-and-set來實施。
但是,您不需要自己實現鎖定。自從C++ 11以來,標準庫已經包含了一個實現。更好的是,它包含更高級別的原子類型(std::atomic
),它提供原子訪問而不顯式鎖定執行(原子類型的實現甚至可以使用更有效的指令來避免鎖定,具體取決於目標架構)。
如果您的標準庫已過時,那麼您可以使用操作系統提供的線程API。它幾乎肯定爲您提供某種互斥體結構。
你的例子表明,你想要在你的線程中執行的所有操作都是對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;
}
如果變量在對象成員函數中,我仍可以實現此代碼嗎? – MagnusHimmler
不知道我是否正確理解你。也許你可以用一個小例子編輯你的問題?但是,如果你的變量是某個成員函數中的局部變量,那麼我很難懷疑你的問題是關於這個變量的競爭條件。 – sigy
我有一個靜態變量,由同一個對象內的兩個不同的函數訪問。但有時第二個函數完全跳過這個變量 – MagnusHimmler
如果你正在使用'pthread's,那麼你可以使用'pthread_mutex_lock'和'pthread_mutex_unlock' –
最簡單的方法,如果你有C++ 11,就是'std :: atomic x;'。 –