C++读写锁

两个模板包装器

unique_lock (C++11)实现可移动的互斥体所有权包装器
写锁包装
shared_lock	(C++14)实现可移动的共享互斥体所有权封装器
读锁包装

C++11读写锁

在C++11中需要自己实现读写锁,下面代码为xin_hen大佬包装好的代码使用了信号量进行实现;
没有效率验证,不能保证某些情况下是否比mutex性能高;

#pragma once
#include<mutex>
#include<condition_variable>

class ReadWriteLock {
private:
	int readWaiting = 0;  //等待读
	int writeWaiting = 0; //等待写
	int reading = 0; //正在读
	int writing = 0;  //正在写
	std::mutex mx;
	std::condition_variable cond;
	bool preferWriter;  //偏向读
public:
	ReadWriteLock(bool isPreferWriter = false) :preferWriter(isPreferWriter) {}

	void readLock() {
		std::unique_lock<std::mutex>lock(mx);
		++readWaiting;
		cond.wait(lock, [&]() {return writing <= 0 && (!preferWriter || writeWaiting <= 0); });
		++reading;
		--readWaiting;
	}

	void writeLock() {
		std::unique_lock<std::mutex>lock(mx);
		++writeWaiting;
		cond.wait(lock, [&]() {return reading <= 0 && writing <= 0; });
		++writing;
		--writeWaiting;
	}

	void readUnLock() {
		std::unique_lock<std::mutex>lock(mx);
		--reading;
		//当前没有读者时,唤醒一个写者
		if(reading<=0)
			cond.notify_one();  
	}

	void writeUnLock() {
		std::unique_lock<std::mutex>lock(mx);
		--writing;
		//唤醒所有读者、写者
		cond.notify_all(); 
	}
};

使用方式:

// 写者优先
ReadWriteLock readWriteLock(true);
{	// 读锁
	readWriteLock.readLock();
	readWriteLock.readUnLock();
}
{	// 写锁
	readWriteLock.writeLock();
	readWriteLock.writeUnLock();
}

C++14读写锁shared_timed_mutex

shared_timed_mutex的原名为“共享超时互斥锁 ”,只是使用者称为读写锁;

普通调用 w/r
lock			// 互斥 若互斥不可用则阻塞
unlock			// 解锁互斥
lock_shared		// 共享 若互斥不可用则阻塞
unlock_shared	// 解锁互斥

立即返回调用	w/r	(与普通调用不同,如果不能使用资源,则立即返回,不解锁)
try_lock		// 尝试锁定互斥,若互斥不可用则返回
try_lock_shared		// 尝试共享锁定互斥,若互斥不可用则返回

超时返回调用 w/r	(for为等待多少时间,until为到指定到具体时间,)
try_lock_for(...);
try_lock_until(...);
try_lock_shared_for(...);
try_lock_shared_until(...);

想要深入研究C++14shared_timed_mutex,请进入详情页签
如果只是简单使用可以看下面的简单使用方式,我一直遵循28原则,所有的知识全部过一遍,弄清楚其中的20%,剩余的80%只要知道有这个东西,需要用时再学习;

使用方式:

#include <shared_mutex>
std::shared_timed_mutex stmtx;
普通使用:
{	// 写
	stmtx.lock();
	stmtx.unlock();
}
{	// 读
	stmtx.lock_shared();
	stmtx.unlock_shared();
}
包装使用:(注意作用范围为{ })
{	// 写
	std::unique_lock<std::shared_timed_mutex> lcx(stmtx);
}
{	// 读
	std::shared_lock<std::shared_timed_mutex> lcx(stmtx);
}
当调用lock()的时,如果有线程获取了共享锁,那么写线程会等待,直到所有共享锁完成释放,才锁定资源,进行修改;
当调用lock_shared()时,如果有写线程获取了互斥锁,那么需要等待
当调用lock_shared()时,如果有读线程获取共享锁,也会直接返回,获取成功。

使用案例:

#include <shared_mutex>
#include <thread>
#include <iostream>

std::shared_timed_mutex stmtx;

void ReadThread()
{
    while (true)
    {
        stmtx.lock_shared();
        std::cout << "thread id = " << std::this_thread::get_id() << " lock shared  read" << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
        stmtx.unlock_shared();
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
}

void WriteThread()
{
    while (true)
    {
        stmtx.lock();
        std::cout << "thread id = " << std::this_thread::get_id() << " lock  write" << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
        stmtx.unlock();
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
}


int main()
{
    for(int i = 0; i < 3; ++i)
    {
        std::thread t(ReadThread);
        t.detach();
    }

    for(int i = 0; i < 2; ++i)
    {
        std::thread t(WriteThread);
        t.detach();
    }

    getchar();
    return 0;
}

C++17读写锁 shared_mutex

C++17的shared_mutex和C++14的shared_timed_mutex类似,只是少了超时控制;

在vscode中使用std::shared_lock<std::shared_mutex>会报错;命名空间 "std" 没有成员 "shared_mutex";
但是在Linux下使用-std=c++17,是可以通过编译的;
vscode希望你能改为shared_timed_mutex,具体原由不太清楚,可能是我自己原因;

在这里插入图片描述

普通调用 w/r
lock			// 互斥 若互斥不可用则阻塞
unlock			// 解锁互斥
lock_shared		// 共享 若互斥不可用则阻塞
unlock_shared	// 解锁互斥

立即返回调用	w/r	(与普通调用不同,如果不能使用资源,则立即返回,不解锁)
try_lock		// 尝试锁定互斥,若互斥不可用则返回
try_lock_shared		// 尝试共享锁定互斥,若互斥不可用则返回

使用方式

#include <shared_mutex>
std::shared_mutex g_mutex;
注意作用域为 { } 作用域结束解锁
普通使用:
std::shared_mutex mutex_;
{	// 写
	mutex_.lock;
	...
    mutex_.unlock;
}
{	// 读
	mutex_.lock_shared();
	...
    mutex_.unlock_shared();
}
包装器使用:
{	// 写
	std::unique_lock<std::shared_mutex> wLock(g_mutex);
}
{	// 读
	std::shared_lock<std::shared_mutex> rLock(g_mutex);
}
shared_mutex为C++17出现
-std=c++17	可以通过编译
-std=c++2a 可以通过编译

注意:在class中使用锁,需要添加 关键字:mutable 描述锁,否则在const成员函数中使用锁会报错;
使用案例

#include <iostream>
#include <mutex>  // 对于 std::unique_lock
#include <shared_mutex>
#include <thread>
 
class ThreadSafeCounter {
 public:
  ThreadSafeCounter() = default;
 
  // 多个线程/读者能同时读计数器的值。
  unsigned int get() const {
    std::shared_lock<std::shared_mutex> lock(mutex_);
    return value_;
  }
 
  // 只有一个线程/写者能增加/写线程的值。
  void increment() {
    std::unique_lock<std::shared_mutex> lock(mutex_);
    value_++;
  }
 
  // 只有一个线程/写者能重置/写线程的值。
  void reset() {
    mutex_.lock_shared();
    value_ = 0;
    mutex_.unlock_shared();
  }
 
 private:
  mutable std::shared_mutex mutex_;
  unsigned int value_ = 0;
};
 
int main() {
  ThreadSafeCounter counter;
 
  auto increment_and_print = [&counter]() {
    for (int i = 0; i < 3; i++) {
      counter.increment();
      std::cout << std::this_thread::get_id() << ' ' << counter.get() << '\n';
 
      // 注意:写入 std::cout 实际上也要由另一互斥同步。省略它以保持示例简洁。
    }
  };
 
  std::thread thread1(increment_and_print);
  std::thread thread2(increment_and_print);
 
  thread1.join();
  thread2.join();
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值