C++17 新增了 std::shared_mutex, 通过shared_mutex 可以实现读写锁的功能,
参考网址 :https://zh.cppreference.com/w/cpp/thread/shared_mutex
shared_mutex可以同时支持多个线程对共享资源同时读,但是只支持一个线程对同一共享资源进行写操作。
shared_mutex 支持共享锁和独占锁,
- std::shared_lock<std::shared_mutex> lock(sharedMutex); //共享锁
- std::unique_lock<std::shared_mutex> lock(sharedMutex); //独占锁
1. shared_mutex 简介
class shared_mutex; | (C++17 起) |
shared_mutex类是一个同步原语,可用于保护共享数据不被多个线程同时访问。与便于独占访问的其他互斥体类型不同,shared_mutex 拥有两个访问级别:
- 共享 - 多个线程能共享同一互斥体的所有权。
- 独占 - 仅一个线程能占有互斥。
若一个线程已获取独占 锁(通过 lock、try_lock),则无其他线程能获取该锁(包括共享的)。
若一个线程已获取共享 锁(通过 lock_shared、try_lock_shared),则无其他线程能获取独占 锁,但可以获取共享 锁。
仅当任何线程均未获取独占 锁时,共享 锁能被多个线程获取。
在一个线程内,同一时刻只能获取一个锁(共享或独占)。
共享互斥体在能由任何数量的线程同时读共享数据,但一个线程只能在无其他线程同时读写时写同一数据时特别有用
排他性锁定 | |
锁定互斥体,若互斥体不可用则阻塞 (公开成员函数) | |
尝试锁定互斥体,若互斥体不可用则返回 (公开成员函数) | |
解锁互斥体 (公开成员函数) | |
共享锁定 | |
为共享所有权锁定互斥体,若互斥体不可用则阻塞 (公开成员函数) | |
尝试为共享所有权锁定互斥体,若互斥体不可用则返回 (公开成员函数) | |
解锁互斥体(共享所有权) (公开成员函数) |
2. 读写锁实现
2.1 通过shared_mutex 实现读写锁
#include <iostream>
#include <shared_mutex>
#include <stdio.h>
#include <thread>
class TreadSafeCounter {
private:
mutable std::shared_mutex m_mtx;
unsigned int m_value = 0;
public:
TreadSafeCounter() = default;
unsigned int get() const {
std::shared_lock lock(m_mtx); // 共享锁(读锁), C++17 能自动推导出模板参数类型
return m_value;
}
void increment() {
std::unique_lock lock(m_mtx); //独占锁(写锁),C++17 能自动推导出模板参数类型
++m_value;
}
void reset() {
std::unique_lock<std::shared_mutex> lock(m_mtx); //共享锁
m_value = 0;
}
};
void test() {
TreadSafeCounter counter;
auto incrementAndPrint = [&counter](std::string threadName) {
for (int i = 0; i < 5; ++i) {
counter.increment();
printf("thread name %s counter = %d \n", threadName.c_str(), counter.get());
}
};
std::thread th1(incrementAndPrint, "thread_1");
std::thread th2(incrementAndPrint, "thread_2");
th1.join();
th2.join();
printf("Main thread counter = %d \n", counter.get());
}
int main() {
test();
return 0;
}
2.2 通过mutex和condition_variable手动实现一个读写锁
#ifndef __READWRITELOCK_H__
#define __READWRITELOCK_H__
#include <mutex>
class ReadWriteMutex {
private:
std::mutex m_mtx;
std::condition_variable m_cond;
int m_readCount = 0; //当m_readCount = 0时,没有上锁; 当m_readCount > 0,读锁, 当m_readCounnt < 0,写锁
public:
ReadWriteMutex() = default;
void ReadLock() {
std::unique_lock<std::mutex> lock(m_mtx);
m_cond.wait(lock, [this]() { return m_readCount >= 0;});
++m_readCount;
}
void ReadUnlock() {
std::unique_lock<std::mutex> lock(m_mtx);
--m_readCount;
if (m_readCount == 0) {
m_cond.notify_one();
}
}
void WriteLock() {
std::unique_lock<std::mutex> lock(m_mtx);
m_cond.wait(lock, [this]() { return m_readCount == 0; });
m_readCount = -1;
}
void WriteUnlock() {
std::unique_lock<std::mutex> lock(m_mtx);
m_readCount = 0;
m_cond.notify_all();
}
};
class ReadLock {
private:
ReadWriteMutex &m_rwMutex;
public:
ReadLock(ReadWriteMutex& readWriteMutex) : m_rwMutex(readWriteMutex) {
m_rwMutex.ReadLock();
}
~ReadLock() {
m_rwMutex.ReadUnlock();
}
void lock() {
m_rwMutex.ReadLock();
}
void unlock() {
m_rwMutex.ReadUnlock();
}
};
class WriteLock {
private:
ReadWriteMutex& m_rwMutex;
public:
WriteLock(ReadWriteMutex& readWriteMutex) : m_rwMutex(readWriteMutex) {
m_rwMutex.WriteLock();
}
~WriteLock() {
m_rwMutex.WriteUnlock();
}
void Lock() {
m_rwMutex.WriteLock();
}
void unlock() {
m_rwMutex.WriteUnlock();
}
};
#endif
测试代码
#include "ReadWriteLock.h"
#include <iostream>
class ThreadSafeCounter
{
public:
ThreadSafeCounter() = default;
// Multiple threads/readers can read the counter's value at the same time.
unsigned int get() const
{
ReadLock lock(m_mutex);
return m_value;
}
// Only one thread/writer can increment/write the counter's value.
void increment()
{
WriteLock lock(m_mutex);
++m_value;
}
// Only one thread/writer can reset/write the counter's value.
void reset()
{
WriteLock lock(m_mutex);
m_value = 0;
}
private:
mutable ReadWriteMutex m_mutex;
unsigned int m_value = 0;
};
void test() {
ThreadSafeCounter counter;
auto increment_and_print = [&counter](std::string threadName)
{
for (int i{}; i != 6; ++i)
{
counter.increment();
printf("thread name %s counter = %d \n", threadName.c_str(), counter.get());
}
};
std::thread thread1(increment_and_print, "thread_1");
std::thread thread2(increment_and_print, "thread_2");
std::thread thread3(increment_and_print, "thread_3");
thread1.join();
thread2.join();
thread3.join();
std::cout << "main thread, count = " << counter.get() << std::endl;
}
int main() {
test();
return 0;
}
标签:std,线程,thread,lock,C++,mutex,shared
From: https://blog.csdn.net/luckyhare999/article/details/142849120