C++11 版不帶自旋鎖的API,我們可以手動實現,有的時候線程執行的功能比較簡單,或者說代碼量較少,如果使用mutex的話,開銷比較大,但是使用mutex的鎖,線程處於非運行態時不佔用CPU,這是其他的線程可以運行,使用自旋鎖時線程被阻塞,但是被阻塞線程依然不會讓出CPU,而是會不斷的while來檢查鎖的狀態,有點浪費CPU,所以自旋鎖一般適用於簡短的不耗時的線程
自旋鎖可以使用如下方式來實現:
class spin_lock {
private:
atomic_flag flag;
public:
spin_lock() = default;
spin_lock(const spin_lock&) = delete;
spin_lock& operator=(const spin_lock) = delete;
void lock() { //acquire spin lock
while (flag.test_and_set());
}
void unlock() { //release spin lock
flag.clear();
}
};
atomic_flag是原子操作的,獲得鎖後會把此變量置爲true,然後另外一個進程就會因爲flag=true而一直在while處執行循環,知道獲得鎖的線程將鎖釋放(將falg置爲false),此時線程的flag.test_and_set()就會返回false,跳出while循環,並把flag置爲true,使用如下:
// 02自旋鎖.cpp : 定義控制檯應用程序的入口點。
//
#include "stdafx.h"
#include <thread>
#include <atomic>
#include <iostream>
#include <cstdio>
using namespace std;
using namespace this_thread;
using namespace chrono;
class spin_lock {
private:
atomic_flag flag;
public:
spin_lock() = default;
spin_lock(const spin_lock&) = delete;
spin_lock& operator=(const spin_lock) = delete;
void lock() { //acquire spin lock
while (flag.test_and_set());
}
void unlock() { //release spin lock
flag.clear();
}
};
int num = 0;
spin_lock splock;
void func()
{
for (int i = 0; i < 100000; ++i)
{
splock.lock();
++num;
//sleep_for(milliseconds(100));
splock.unlock();
}
}
int main()
{
cout << "程序開始執行" << endl;
thread t1(func);
thread t2(func);
thread t3(func);
t1.join();
t2.join();
t3.join();
cout << num << endl;
return 0;
}
另外需要注意的是,在鎖中不能加休眠,假如加入休眠,線程A獲得鎖之後進行休眠,此時並未釋放鎖,flag還是true,但是在CPU調度下會執行線程B,線程B此時就會檢查鎖的狀態,由於A並沒有釋放鎖,所以線程B會死在while中,導致CPU無法調度運行其他線程,也就無法運行線程A的解鎖,如此會產生死鎖