使用讀寫鎖的好處是所有的讀操作都能同時進行,而寫操作需要獨占互斥量。這樣能保證讀操作不會互相阻塞等待。而他們的共同競争者是那些獨占互斥量的寫操作。标準模闆庫中提供了std::shared_lock(共享鎖)和std::shared_mutex(共享互斥量)。而閱讀源碼可以看到,shared_lock再構造的時候其實調用互斥量的lock_shared()函數。
template<class _Mutex>
class shared_lock
{ // shareable lock
public:
typedef _Mutex mutex_type;
shared_lock() noexcept
: _Pmtx(nullptr), _Owns(false)
{ // default construct
}
explicit shared_lock(mutex_type& _Mtx)
: _Pmtx(_STD addressof(_Mtx)), _Owns(true)
{ // construct with mutex and lock shared
_Mtx.lock_shared(); //此處調用了互斥量的lock_shared()函數。
}
//等等。
//.........
}
而隻有std::shared_mutex提供了lock_shared()函數。是以我們需要定義我們的互斥量為std::shared_mutex, 讀操作的鎖為std::shared_lock<std::shared_mutex> lk(_lock); 而寫操作的鎖為 std::unique_lock<std::shared_mutex> lk(_lock); 因為寫操作要獨占互斥量,是以使用std::unique_lock。提供以下代碼作為參考:
//thread_safe_counter.h檔案。
#pragma once
#include <shared_mutex>
class thread_safe_counter {
public:
thread_safe_counter() : _value(0) {}
int read_value() const;
void write_value(int value);
private:
mutable std::shared_mutex _lock;
int _value;
};
//thread_safe_counter.cpp 檔案。
#include "pch.h"
#include "thread_safe_counter.h"
#include <iostream>
int thread_safe_counter::read_value() const
{
std::shared_lock<std::shared_mutex> lk(_lock);
std::cout << "讀取線程拿到了共享鎖: thread_id : " << std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "讀取線程執行了2秒: thread_id : " << std::this_thread::get_id() << std::endl;
return _value;
}
void thread_safe_counter::write_value(int value)
{
std::unique_lock<std::shared_mutex> lk(_lock);
std::cout << "寫入線程拿到了共享鎖: thread_id : " << std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout << "寫入線程執行了3秒: thread_id : " << std::this_thread::get_id() << std::endl;
_value = value;
}
//main函數檔案。
#include "pch.h"
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include "thread_safe_counter.h"
int main()
{
thread_safe_counter couter;
std::vector<std::thread> vecs;
for (int i = 0; i < 5; i++) {
std::thread a(&thread_safe_counter::read_value, &couter);
vecs.push_back(std::move(a));
}
std::thread b(&thread_safe_counter::write_value, &couter, 2);
for (int i = 0; i < 5; i++) {
vecs[i].join();
}
b.join();
return 0;
}
定義了5個讀線程和1個寫線程。運作結果如下, 讀線程同時進行,因為使用了std::shared_lock<std::shared_mutex> lk(_lock)。而讀線程差不多執行2秒,所有讀線程執行完之後,寫線程才拿到互斥量。可以看到先執行的讀線程再所有讀線程中不一定是先執行完的。
