C++關於鎖的總結(一)
線程中的鎖分為兩種,互斥鎖和共享鎖。
相關的頭文件有<mutex>
,<shared_mutex>
,前者具有std::unique_lock
操作,用於實現互斥功能,后者具有std::shared_lock
操作,用於完成共享鎖操作。
這里先討論std::shared_mutex
這個類。
共享鎖
如果需要使用共享鎖,則需要使用到std::shared_mutex
這個類。具體講解見這里
該鎖可用於保護被多個線程同時訪問的共享數據。
std::shared_mutex
有兩種訪問級別:
- 共享:多個線程可以共享這個鎖的擁有權。一般用於數據的讀操作,防止數據被寫修改。
- 互斥:僅僅一個線程可以擁有這個鎖。一般用於寫操作。
如果一個線程已經獲取了互斥鎖,則其他線程都無法獲取該鎖。
如果一個線程已經獲取了共享鎖,則其他任何線程都無法獲取互斥鎖,但是可以獲取共享鎖。
說到這里,為了實現該鎖的互斥和共享,不得不介紹std::shared_lock
和std::unique_lock
這兩個模板。前者定義在<shared_mutex>
,后着定義在<mutex>
中。
在下面的代碼中均以測試過,編譯選項為--std=c++1z -pthread
;
由於c++中的cout
不是線程安全的函數,所以給cout
輸出加上了互斥鎖。
共享鎖的代碼示例
#include <shared_mutex>
#include <mutex>
#include <iostream>
#include <thread>
#include <chrono>
std::shared_mutex test_lock;
std::mutex cout_lock;
int arr[3] = {11, 22, 33};
void unique_lock_demo(int id)
{
std::unique_lock lock{test_lock};
for(int i =0; i < 3; i++)
{
arr[i] = i + 100 * id;
}
for(int i = 0; i < 3; i++)
{
std::unique_lock pl(cout_lock);
std::cout << "In unique: " << id << ": " << arr[i] << std::endl;
pl.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
void shared_lock_demo(int id)
{
std::shared_lock lock{test_lock};
for(int i = 0; i < 3; i++)
{
std::unique_lock pl(cout_lock);
std::cout << "In shared " << id << ": " << arr[i] << std::endl;
pl.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
int main()
{
std::thread t3(unique_lock_demo,3);
std::thread t4(unique_lock_demo,4);
std::thread t1(shared_lock_demo,1);
std::thread t2(shared_lock_demo,2);
t1.join();
t2.join();
t3.join();
t4.join();
return 0;
}
輸出為:
In unique: 3: 300
In unique: 3: 301
In unique: 3: 302
In shared 1: 300
In shared 2: 300
In shared 1: 301
In shared 2: 301
In shared 1: 302
In shared 2: 302
In unique: 4: 400
In unique: 4: 401
In unique: 4: 402
從這個輸出可以看出:
-
如果一個線程已經獲取了共享鎖,則其他任何線程都無法獲取互斥鎖,但是可以獲取共享鎖。
-
從這個輸出可以看出,驗證了如果一個線程已經獲取了互斥鎖,則其他線程都無法獲取該鎖。
注:關於上述代碼有的平台運行不了,可以運行下面的代碼
#include <shared_mutex>
#include <mutex>
#include <iostream>
#include <thread>
#include <chrono>
std::shared_mutex test_lock;
std::mutex cout_lock;
int arr[3] = {11, 22, 33};
void unique_lock_demo(int id)
{
std::unique_lock<std::shared_mutex> lock(test_lock);
for(int i =0; i < 3; i++)
{
arr[i] = i + 100 * id;
}
for(int i = 0; i < 3; i++)
{
std::unique_lock<std::mutex> pl(cout_lock);
std::cout << "In unique: " << id << ": " << arr[i] << std::endl;
pl.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
void shared_lock_demo(int id)
{
std::shared_lock<std::shared_mutex> lock(test_lock);
for(int i = 0; i < 3; i++)
{
std::unique_lock<std::mutex> pl(cout_lock);
std::cout << "In shared " << id << ": " << arr[i] << std::endl;
pl.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
int main()
{
std::thread t3(unique_lock_demo,3);
std::thread t1(shared_lock_demo,1);
std::thread t2(shared_lock_demo,2);
std::this_thread::sleep_for(std::chrono::seconds(4));
std::thread t4(unique_lock_demo,4);
t1.join();
t2.join();
t3.join();
t4.join();
return 0;
}