news 2026/6/10 16:12:31

【多线程】共享锁 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/6/10 10:42:14

一站式深度学习环境:PyTorch-CUDA-v2.7集成CUDA工具包

一站式深度学习环境&#xff1a;PyTorch-CUDA-v2.7集成CUDA工具包 在深度学习项目开发中&#xff0c;最让人头疼的往往不是模型设计本身&#xff0c;而是“环境能不能跑起来”这个问题。你有没有遇到过这样的场景&#xff1f;从GitHub拉下一个热门项目&#xff0c;满怀期待地运…

作者头像 李华
网站建设 2026/6/10 10:40:20

【Agent】智能体大时代:百家争鸣下的AI新纪元

Agent智能体大时代&#xff1a;百家争鸣下的AI新纪元 引言&#xff1a;当AI学会了"自己干活" 2026年AI Agent 必然会烂大街&#xff01;我说的&#xff01;&#xff01; 还记得2023年GPT刚火的时候&#xff0c;大家都在讨论"AI能写代码了"、“AI能画画了”…

作者头像 李华
网站建设 2026/6/10 10:42:39

Python 函数参数全攻略:从入门到精通(2026版)

目录Python 函数参数全攻略&#xff1a;从入门到精通1. 前置知识 (Prerequisites)2. 核心概念&#xff1a;形参与实参3. Python 参数详解 (Step-by-Step Guide)3.1 位置参数 (Positional Arguments)3.2 关键字参数 (Keyword Arguments)3.3 默认参数 (Default Arguments)3.4 可变…

作者头像 李华
网站建设 2026/6/10 11:58:34

springboot电影院售票选座管理系统的设计与实现(编号:3463212)

目录已开发项目效果实现截图关于博主开发技术介绍核心代码参考示例1.建立用户稀疏矩阵&#xff0c;用于用户相似度计算【相似度矩阵】2.计算目标用户与其他用户的相似度系统测试总结源码文档获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;已开发…

作者头像 李华
网站建设 2026/6/10 12:35:31

基于Spring Boot的顺达驾校管理系统

基于Spring Boot的顺达驾校管理系统是一个专门为驾校运营管理而设计的项目&#xff0c;以下是关于该系统的详细介绍&#xff1a; 一、系统概述 该系统采用Spring Boot框架作为后端开发技术&#xff0c;结合Java语言的面向对象特性和丰富的类库&#xff0c;确保了系统的稳定性和…

作者头像 李华