目录
1.前言
2.正文
3.代码和验证
1.前言:
前几日上班时,因为底层逻辑修改。多线程情况下,许多函数如果依然按照原有的锁去串行执行,效率会很低。(原先是 std::mutex ,以及每个函数用的锁是std::lock_guard)
这时我的领导给我新任务,修改多线程的锁,在修改后,要求函数 1 函数2 要能并发执行,且前两者并发执行时与函数 3 函数4 函数5是互斥的。而函数 3,4,5与所有函数都互斥。(例如函数3运行的时候,函数1 2 4 5都是卡着等待函数3执行完毕再继续执行)。
我实在是不会做,这个时候请教我领导,他告诉我用读写锁就能解决问题。c++读写锁的应用也就是使用 shared_mutex,shared_lock,这两者者解决问题。
这是本人对此次经历的记录,可能写的并不太好。可以参考他人文章和cppRefrecne官方文章。
C++多线程——读写锁shared_lock/shared_mutex_princeteng的博客-CSDN博客_shared_lock
std::shared_lock - cppreference.com
2.正文:关于shared_mutex,shared_lock的知识和描述
shared_mutex
类是一个同步原语,可用于保护共享数据不被多个线程同时访问。与便于独占访问的其他互斥类型不同,shared_mutex 拥有二个访问级别:
- 共享 - 多个线程能共享同一互斥的所有权。
- 独占性 - 仅一个线程能占有互斥。
若一个线程已获取独占性锁(通过 lock 、 try_lock ),则无其他线程能获取该锁(包括共享的)。
仅当任何线程均未获取独占性锁时,共享锁能被多个线程获取(通过 lock_shared 、 try_lock_shared )。
在一个线程内,同一时刻只能获取一个锁(共享或独占性)。
共享互斥体在能由任何数量的线程同时读共享数据,但一个线程只能在无其他线程同时读写时写同一数据时特别有用。
shared_mutex
类满足共享互斥体 (SharedMutex) 和标准布局类型 (StandardLayoutType) 的所有要求。
以上是cppreferenced的原文。翻译一遍就是这样的逻辑
当Mutex是shared_mutex
的时候
1.当有函数使用共享锁时,能够与其他享有共享锁的函数也能并发同步执行。而和所有独占锁的函数是互斥的。
2.当有一个函数使用独占锁时,其他所有的用同一个Mutex带锁的函数都是与其互斥的。
那么这个情况就和我所遇到的需求是完全一致的。
已知的独占锁
锁定互斥,若互斥不可用则阻塞 (公开成员函数) | |
尝试锁定互斥,若互斥不可用则返回 (公开成员函数) | |
解锁互斥 (公开成员函数) | |
std::unique_lock | 自动加锁和解锁 |
std::lock_guard | 自动加锁和解锁 |
已知的共享锁
共享锁定 | |
为共享所有权锁定互斥,若互斥不可用则阻塞 (公开成员函数) | |
尝试为共享所有权锁定互斥,若互斥不可用则返回 (公开成员函数) | |
解锁互斥(共享所有权) (公开成员函数) | |
std::shared_lock | 自动加锁和解锁 |
3.代码验证
以下代码是本人在vs2019,c++最新标准下运行的。
可以直接复制过去看效果,也可以自己稍作修改进行验证
#include <iostream>
#include <string>
#include <mutex>
#include <thread>
#include <shared_mutex>
#include <Windows.h>
std::shared_mutex g_sMutex;
void writeTime(const std::string funName ,int time) {
for (size_t i = 1; i < time; i++) {
std::string outPut = funName + ":" + std::to_string(time);
std::cout << outPut << std::endl;
Sleep(1000);
}
}
void shared_1(int seconds) {
std::shared_lock<std::shared_mutex> theLock(g_sMutex);
writeTime("shared_1" , seconds);
}
void shared_2(int seconds) {
std::shared_lock<std::shared_mutex> theLock(g_sMutex);
writeTime("shared_2", seconds);
}
void unique_1(int seconds) {
std::unique_lock<std::shared_mutex> lck(g_sMutex);
writeTime("unique_1", seconds);
}
void unique_2(int seconds) {
std::unique_lock<std::shared_mutex> lck(g_sMutex);
writeTime("unique_2", seconds);
}
void nomralSuo(int seconds) {
std::lock_guard<std::shared_mutex> lck(g_sMutex);
writeTime("nomralSuo", seconds);
}
int main()
{
std::vector<std::thread> vecThread;
vecThread.push_back(std::thread(nomralSuo, 10));
vecThread.push_back(std::thread(shared_1, 10));
vecThread.push_back(std::thread(shared_2, 10));
vecThread.push_back(std::thread(unique_1, 10));
vecThread.push_back(std::thread(unique_2, 10));
for (auto & oneThread : vecThread)
{
oneThread.join();
}
}