news 2026/8/10 3:36:21

【多线程】共享锁 Shared Lock

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【多线程】共享锁 Shared Lock

共享互斥锁(SharedMutex)详解

什么是读写锁?

读写锁是一种特殊的锁,允许多个读者同时读取,但写者必须独占

普通互斥锁: ┌─────────────────────────────────┐ │ 同一时间只能有一个线程(读或写) │ └─────────────────────────────────┘ 读写锁: ┌─────────────────────────────────┐ │ 读者1 读者2 读者3 ← 可以同时 │ │ │ │ 写者1 ← 必须独占(没有其他读/写)│ └─────────────────────────────────┘

为什么需要读写锁?

场景:配置文件 - 读取配置:非常频繁(每秒1000次) - 修改配置:很少(每天几次) 用普通mutex:所有操作串行,性能差 用读写锁:读操作并发,性能好

状态图

┌─────────────────────────────────────────────┐ │ 空闲状态 │ │ readers_=0, writer_=false │ └──────────────┬──────────────┬───────────────┘ │ │ lock_shared() lock() │ │ ▼ ▼ ┌──────────────────┐ ┌──────────────────┐ │ 读取状态 │ │ 写入状态 │ │ readers_>0 │ │ writer_=true │ │ writer_=false │ │ readers_=0 │ │ │ │ │ │ 允许更多读者加入 │ │ 其他所有人等待 │ └──────────────────┘ └──────────────────┘

带注释的代码

#include<condition_variable>#include<mutex>classSharedMutex{private:std::mutex mtx_;// Internal mutex to protect statestd::condition_variable cv_;// For threads to wait and wake upintreaders_=0;// Count of active readersboolwriter_=false;// Is there an active writer?public:// ============================================// Acquire shared (read) lock// Multiple threads can hold this simultaneously// ============================================voidlock_shared(){std::unique_lock<std::mutex>lock(mtx_);// Wait until no writer is active// Readers can coexist with other readers// But must wait if a writer is workingcv_.wait(lock,[this](){return!writer_;});// Now safe to read, increment reader count++readers_;// Note: lock releases here, other readers can enter}// ============================================// Release shared (read) lock// ============================================voidunlock_shared(){std::unique_lock<std::mutex>lock(mtx_);// One less reader--readers_;// If I'm the last reader, wake up waiting writersif(readers_==0){cv_.notify_all();}}// ============================================// Acquire exclusive (write) lock// Only one thread can hold this// No readers allowed during write// ============================================voidlock(){std::unique_lock<std::mutex>lock(mtx_);// Wait until:// 1. No other writer is active// 2. No readers are readingcv_.wait(lock,[this](){return!writer_&&readers_==0;});// Now I'm the exclusive writerwriter_=true;}// ============================================// Release exclusive (write) lock// ============================================voidunlock(){std::unique_lock<std::mutex>lock(mtx_);// Done writingwriter_=false;// Wake up everyone (readers and writers)// They will compete for the lockcv_.notify_all();}};// ============================================// RAII wrapper for shared lock// Automatically locks on construction// Automatically unlocks on destruction// ============================================template<typenameMutex>classSharedLock{private:Mutex&mtx_;public:// Constructor: acquire shared lockexplicitSharedLock(Mutex&mtx):mtx_(mtx){mtx_.lock_shared();}// Destructor: release shared lock// Called automatically when object goes out of scope~SharedLock(){mtx_.unlock_shared();}// Non-copyable (prevent double unlock)SharedLock(constSharedLock&)=delete;SharedLock&operator=(constSharedLock&)=delete;};// ============================================// RAII wrapper for exclusive lock// ============================================template<typenameMutex>classUniqueLock{private:Mutex&mtx_;public:// Constructor: acquire exclusive lockexplicitUniqueLock(Mutex&mtx):mtx_(mtx){mtx_.lock();}// Destructor: release exclusive lock~UniqueLock(){mtx_.unlock();}// Non-copyableUniqueLock(constUniqueLock&)=delete;UniqueLock&operator=(constUniqueLock&)=delete;};

使用示例

#include<iostream>#include<thread>#include<vector>SharedMutex rw_mutex;intshared_data=0;// 读者线程voidreader(intid){SharedLock<SharedMutex>lock(rw_mutex);// 自动获取读锁std::cout<<"Reader "<<id<<" reads: "<<shared_data<<std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(100));// 自动释放读锁(析构时)}// 写者线程voidwriter(intid){UniqueLock<SharedMutex>lock(rw_mutex);// 自动获取写锁++shared_data;std::cout<<"Writer "<<id<<" writes: "<<shared_data<<std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(100));// 自动释放写锁(析构时)}intmain(){std::vector<std::thread>threads;// 启动多个读者和写者for(inti=0;i<3;i++){threads.emplace_back(reader,i);}threads.emplace_back(writer,0);for(inti=3;i<6;i++){threads.emplace_back(reader,i);}threads.emplace_back(writer,1);for(auto&t:threads){t.join();}return0;}

执行时序图

时间 ──────────────────────────────────────────► Reader1: ████████ Reader2: ████████ (多个读者同时读) Reader3: ████████ Writer0: ████████ (写者独占) Reader4: ████████ Reader5: ████████ (又可以多个读者同时) Reader6: ████████ Writer1: ████████ (写者独占)

案例:

#include<chrono>#include<iostream>#include<thread>#include<vector>#include"my_shared.h"classDataStore{private:intdata_=0;mutableSharedMutex mtx_;public:intread()const{SharedLock<SharedMutex>lock(mtx_);std::cout<<"[Thread "<<std::this_thread::get_id()<<"] Reading: "<<data_<<"\n";std::this_thread::sleep_for(std::chrono::milliseconds(100));returndata_;}voidwrite(intvalue){UniqueLock<SharedMutex>lock(mtx_);std::cout<<"[Thread "<<std::this_thread::get_id()<<"] Writing: "<<value<<"\n";data_=value;std::this_thread::sleep_for(std::chrono::milliseconds(100));}};intmain(){DataStore store;std::vector<std::thread>threads;// 3 readersfor(inti=0;i<3;++i){threads.emplace_back([&store](){for(intj=0;j<3;++j){store.read();}});}// 1 writerthreads.emplace_back([&store](){for(intj=1;j<=3;++j){store.write(j*100);}});for(auto&t:threads){t.join();}return0;}

总结

概念说明
readers_当前正在读的线程数
writer_是否有线程正在写
lock_shared()获取读锁,等待没有写者
lock()获取写锁,等待没有读者和写者
RAII构造时加锁,析构时解锁,防止忘记解锁

写者优先的读写锁(Writer Priority SharedMutex)详解

为什么需要写者优先?

普通读写锁的问题: 时间 ─────────────────────────────────────────────► Reader1: ████████ Reader2: ████████ Reader3: ████████ Reader4: ████████ Reader5: ████████ ... Writer: 等待...等待...等待...等待... (饿死了!) 读者不断进来,写者永远拿不到锁 = 写者饥饿
写者优先: 时间 ─────────────────────────────────────────────► Reader1: ████████ Reader2: ████████ ↓ 写者来了,新读者必须等待 Writer: ████████ ↓ 写者完成,读者才能继续 Reader3: ████████ Reader4: ████████

状态图

┌─────────────────────────────────────────────────────┐ │ 空闲状态 │ │ readers_=0, writer_=false, waiting_writers_=0 │ └───────────────┬─────────────────────┬───────────────┘ │ │ lock_shared() lock() │ │ ▼ ▼ ┌────────────────────┐ ┌────────────────────────────┐ │ 读取状态 │ │ 写入状态 │ │ readers_ > 0 │ │ writer_ = true │ │ writer_ = false │ │ readers_ = 0 │ │ │ │ │ │ 如果 waiting_writers_>0 │ │ │ │ 新读者不能进入! │ │ │ └────────────────────┘ └────────────────────────────┘

关键区别

普通读写锁: ┌─────────────────────────────────────────┐ │ 读者等待条件: !writer_ │ │ → 只要没人写,读者就进来 │ └─────────────────────────────────────────┘ 写者优先读写锁: ┌─────────────────────────────────────────┐ │ 读者等待条件: !writer_ && waiting_writers_==0 │ │ → 没人写 AND 没人等着写,读者才能进来 │ └─────────────────────────────────────────┘

带注释的代码

#include<condition_variable>#include<mutex>classSharedMutexWriterPriority{private:std::mutex mtx_;std::condition_variable reader_cv_;// Readers wait on thisstd::condition_variable writer_cv_;// Writers wait on thisintreaders_=0;// Count of active readersintwaiting_writers_=0;// Count of writers waiting in queueboolwriter_=false;// Is there an active writer?public:// ============================================// Acquire shared (read) lock// Writers have priority over new readers!// ============================================voidlock_shared(){std::unique_lock<std::mutex>lock(mtx_);// Wait if:// 1. A writer is currently writing, OR// 2. Writers are waiting (give them priority!)//// This is the KEY difference from basic SharedMutex// New readers must wait for all waiting writersreader_cv_.wait(lock,[this](){return!writer_&&waiting_writers_==0;});// Safe to read now++readers_;}// ============================================// Release shared (read) lock// ============================================voidunlock_shared(){std::unique_lock<std::mutex>lock(mtx_);--readers_;// If I'm the last reader, wake up ONE waiting writer// (not all, just one - more efficient)if(readers_==0){writer_cv_.notify_one();}}// ============================================// Acquire exclusive (write) lock// ============================================voidlock(){std::unique_lock<std::mutex>lock(mtx_);// Register myself as waiting writer// This blocks new readers from entering!++waiting_writers_;// Wait until no writer AND no readerswriter_cv_.wait(lock,[this](){return!writer_&&readers_==0;});// Got the lock, no longer waiting--waiting_writers_;writer_=true;}// ============================================// Release exclusive (write) lock// ============================================voidunlock(){std::unique_lock<std::mutex>lock(mtx_);writer_=false;// Priority: wake writers firstif(waiting_writers_>0){// More writers waiting, let them go firstwriter_cv_.notify_one();}else{// No writers waiting, let all readers goreader_cv_.notify_all();}}};

两种读写锁对比

普通读写锁 写者优先读写锁 ────────── ────────────── condition_variable 1个(共用) 2个(分开) 读者等待条件 !writer_ !writer_ && waiting_writers_==0 写者等待条件 !writer_ && !writer_ && readers_==0 readers_==0 unlock时 notify_all 先notify写者 没写者再notify读者 优点 简单公平 写者不会饿死 缺点 写者可能饿死 读者可能饿死

执行时序对比

场景: R1, R2进入 → W1请求 → R3, R4请求 → W1完成 → W2请求 普通读写锁: ──────────────────────────────────────────────────────────► R1: ████████████████████ R2: ████████████████████ R3: ████████████████████████ ← R3进入(不管W1在等) R4: ████████████████████ ← R4进入(不管W1在等) W1: ████████ ← 等很久! W2: ████████ 写者优先: ──────────────────────────────────────────────────────────► R1: ████████████ R2: ████████████ ↓ W1开始等待,阻止新读者 W1: ████████ W2: ████████ ← W2优先 R3: ████████ ← 写者都完成后 R4: ████████

使用示例

#include<iostream>#include<thread>#include<vector>#include<chrono>SharedMutexWriterPriority rw_mutex;intshared_data=0;voidreader(intid){std::cout<<"Reader "<<id<<" waiting..."<<std::endl;rw_mutex.lock_shared();std::cout<<"Reader "<<id<<" reading: "<<shared_data<<std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(100));rw_mutex.unlock_shared();std::cout<<"Reader "<<id<<" done"<<std::endl;}voidwriter(intid){std::cout<<"Writer "<<id<<" waiting..."<<std::endl;rw_mutex.lock();++shared_data;std::cout<<"Writer "<<id<<" writing: "<<shared_data<<std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(100));rw_mutex.unlock();std::cout<<"Writer "<<id<<" done"<<std::endl;}intmain(){std::vector<std::thread>threads;// 先启动读者threads.emplace_back(reader,1);threads.emplace_back(reader,2);std::this_thread::sleep_for(std::chrono::milliseconds(10));// 写者请求threads.emplace_back(writer,1);std::this_thread::sleep_for(std::chrono::milliseconds(10));// 更多读者请求 (会被阻塞,因为写者在等待)threads.emplace_back(reader,3);threads.emplace_back(reader,4);for(auto&t:threads){t.join();}return0;}

总结

概念说明
waiting_writers_等待中的写者数量,用于阻止新读者
reader_cv_读者专用的条件变量
writer_cv_写者专用的条件变量
核心思想写者开始等待时,新读者就不能进入
适用场景写操作重要、不能延迟的场景
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/9 5:02:54

谁是未来“宝藏”?计算机类专业避坑攻略:18个方向深度解析

一次搞懂计算机类18个本科专业方向的区别&#xff0c;谁是“宝藏”谁是“天坑”&#xff1f; 随着科技进步的日新月异&#xff0c;互联网在日常生活中所扮演的角色越来越重要。数字化、信息化的时代里&#xff0c;计算机类专业无疑是当今高考最热门且最具发展前景的志愿填报方…

作者头像 李华
网站建设 2026/8/9 5:02:52

清华镜像加速下载:获取PyTorch-CUDA-v2.7镜像的最快方式

清华镜像加速下载&#xff1a;获取PyTorch-CUDA-v2.7镜像的最快方式 在深度学习项目开发中&#xff0c;最令人头疼的往往不是模型调参&#xff0c;而是环境搭建——明明代码没问题&#xff0c;却因为 PyTorch 和 CUDA 版本不匹配、依赖冲突或下载太慢导致“在我机器上跑不了”…

作者头像 李华
网站建设 2026/8/9 5:02:50

PyTorch-CUDA-v2.7镜像内置Jupyter,支持在线调试与可视化

PyTorch-CUDA-v2.7镜像内置Jupyter&#xff0c;支持在线调试与可视化 在深度学习项目中&#xff0c;最让人头疼的往往不是模型设计本身&#xff0c;而是环境搭建——“为什么代码在我机器上跑得好好的&#xff0c;换台设备就报错&#xff1f;”这类问题几乎成了每个AI工程师的噩…

作者头像 李华
网站建设 2026/8/9 5:02:47

如何在Jupyter Notebook中使用PyTorch-CUDA-v2.7镜像?详细图文教程

如何在 Jupyter Notebook 中使用 PyTorch-CUDA-v2.7 镜像&#xff1f;实战指南 你有没有遇到过这样的场景&#xff1a;刚拿到一台新服务器&#xff0c;兴致勃勃准备跑深度学习模型&#xff0c;结果花了整整一个下午还在折腾 CUDA 版本、cuDNN 兼容性、PyTorch 安装失败……最后…

作者头像 李华
网站建设 2026/7/30 23:47:12

图像去雾:FSB-Dehazing-Framework,未成功

下载 https://github.com/superwsc/FSB-Dehazing-Framework 安装anaconda https://blog.csdn.net/quantum7/article/details/156384942 安装相关 sudo apt-get install cmake build-essential libjpeg-dev libpng-dev conda create -n pytorch1 python3.7 conda activate …

作者头像 李华