天天看點

C++并發與多線程-使用讀寫鎖

使用讀寫鎖的好處是所有的讀操作都能同時進行,而寫操作需要獨占互斥量。這樣能保證讀操作不會互相阻塞等待。而他們的共同競争者是那些獨占互斥量的寫操作。标準模闆庫中提供了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秒,所有讀線程執行完之後,寫線程才拿到互斥量。可以看到先執行的讀線程再所有讀線程中不一定是先執行完的。

C++并發與多線程-使用讀寫鎖