C++ 读写锁 shared_mutex

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 拥有两个访问级别:

  • 共享 - 多个线程能共享同一互斥体的所有权。
  • 独占 - 仅一个线程能占有互斥。

若一个线程已获取独占 锁(通过 locktry_lock),则无其他线程能获取该锁(包括共享的)。

若一个线程已获取共享 锁(通过 lock_sharedtry_lock_shared),则无其他线程能获取独占 锁,但可以获取共享 锁。

仅当任何线程均未获取独占 锁时,共享 锁能被多个线程获取。

在一个线程内,同一时刻只能获取一个锁(共享独占)。

共享互斥体在能由任何数量的线程同时读共享数据,但一个线程只能在无其他线程同时读写时写同一数据时特别有用

排他性锁定

lock

锁定互斥体,若互斥体不可用则阻塞
(公开成员函数)

try_lock

尝试锁定互斥体,若互斥体不可用则返回
(公开成员函数)

unlock

解锁互斥体
(公开成员函数)
共享锁定

lock_shared

为共享所有权锁定互斥体,若互斥体不可用则阻塞
(公开成员函数)

try_lock_shared

尝试为共享所有权锁定互斥体,若互斥体不可用则返回
(公开成员函数)

unlock_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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值