C++:线程当中的锁专题

devtools/2025/2/22 15:29:56/

在 C++ 多线程编程中,线程同步是确保程序正确运行的关键环节,而锁机制则是实现线程同步的重要手段。

一、线程的同步之互斥锁

1.1 互斥锁的概念

互斥锁(Mutex,即 Mutual Exclusion 的缩写)是一种最基本的线程同步工具,用于保证在同一时刻只有一个线程能够访问共享资源,从而避免数据竞争和不一致的问题。其工作原理就像一个房间的钥匙,同一时间只有拿到钥匙的线程才能进入房间(访问共享资源),其他线程必须等待钥匙被释放后才能尝试获取。

1.2 互斥锁的使用场景

当多个线程需要访问和修改共享数据,且这些操作不是原子操作时,就需要使用互斥锁来保护共享数据。例如,在一个多线程的银行账户管理系统中,多个线程可能同时对账户余额进行取款和存款操作,如果不加以同步,就可能导致账户余额出现错误。

1.3 互斥锁的使用方法

在 C++ 中,使用头文件来操作互斥锁。

#include <iostream>
#include <mutex>
#include <thread>std::mutex mtx;
int sharedData = 0;void increment() {mtx.lock();sharedData++;mtx.unlock();
}int main() {std::thread threads[10];for (int i = 0; i < 10; ++i) {threads[i] = std::thread(increment);}for (auto& th : threads) {th.join();}std::cout << "Final value of sharedData: " << sharedData << std::endl;return 0;
}

std::thread threads[10];:定义了一个包含 10 个 std::thread 对象的数组 threads,用于存储创建的线程。
for (int i = 0; i < 10; ++i) { threads[i] = std::thread(increment); }:使用 for 循环创建 10 个线程,每个线程都执行 increment 函数。std::thread(increment) 会启动一个新线程并将 increment 函数作为线程的执行体。
for (auto& th : threads) { th.join(); }:使用范围 for 循环遍历 threads 数组,调用每个线程的 join 方法。join 方法会阻塞主线程,直到对应的子线程执行完毕。这样可以确保主线程在所有子线程执行完毕后再继续执行后续代码。

std::mutex mtx定义了一个互斥锁,increment函数在访问和修改sharedData之前,先通过mtx.lock()获取锁,操作完成后通过mtx.unlock()释放锁,确保了同一时间只有一个线程能修改sharedData。

二、读写锁

2.1 读写锁的概念

读写锁(Read-Write Lock)是一种特殊的同步机制,它区分了读操作和写操作。允许多个线程同时进行读操作,因为读操作不会修改共享数据,不会产生数据竞争;但只允许一个线程进行写操作,并且在写操作时不允许其他线程进行读或写操作,以保证数据的一致性。

2.2 读写锁的使用场景

当共享资源的读操作远远多于写操作时,使用读写锁可以显著提高程序的性能。例如,在一个多线程的数据库查询系统中,大量线程可能同时进行数据查询(读操作),而只有少数线程会进行数据更新(写操作)。

2.3 读写锁的使用方法

在 C++ 中,可以使用<shared_mutex>头文件来操作读写锁。

#include <iostream>
#include <shared_mutex>
#include <thread>std::shared_mutex rwMutex;
int sharedValue = 0;void read() {rwMutex.lock_shared();std::cout << "Reading value: " << sharedValue << std::endl;rwMutex.unlock_shared();
}void write() {rwMutex.lock();sharedValue++;std::cout << "Writing value: " << sharedValue << std::endl;rwMutex.unlock();
}int main() {std::thread readThreads[5];std::thread writeThread(write);for (int i = 0; i < 5; ++i) {readThreads[i] = std::thread(read);}for (auto& th : readThreads) {th.join();}writeThread.join();return 0;
}

std::shared_mutex rwMutex定义了一个读写锁。read函数使用lock_shared进行读锁定,允许多个线程同时读;write函数使用lock进行写锁定,确保同一时间只有一个线程能写。

三、互斥锁非阻塞式锁

3.1 非阻塞式锁的概念

非阻塞式锁是指线程在尝试获取锁时,如果锁当前被其他线程占用,不会阻塞等待,而是立即返回一个状态值,告知线程获取锁的结果,线程可以根据这个结果决定后续的操作。

3.2 非阻塞式锁的使用场景

在一些对响应时间要求较高,且线程不能长时间阻塞的场景中,非阻塞式锁非常有用。例如,在一个实时性要求较高的图形界面应用中,线程需要快速响应用户的操作,不能因为等待锁而导致界面卡顿。

3.3 非阻塞式锁的使用方法

在 C++ 中,std::mutex提供了try_lock方法来实现非阻塞式加锁。

#include <iostream>
#include <mutex>
#include <thread>std::mutex mtx;
int sharedResource = 0;void attemptAccess() {if (mtx.try_lock()) {std::cout << "Thread got the lock." << std::endl;sharedResource++;mtx.unlock();} else {std::cout << "Thread couldn't get the lock." << std::endl;}
}int main() {std::thread threads[3];for (int i = 0; i < 3; ++i) {threads[i] = std::thread(attemptAccess);}for (auto& th : threads) {th.join();}return 0;
}

attemptAccess函数使用try_lock尝试获取锁,如果获取成功则进行操作,否则直接返回。

四、读写锁非阻塞式上锁

4.1 读写锁非阻塞式上锁的概念

与互斥锁的非阻塞式上锁类似,读写锁的非阻塞式上锁允许线程在尝试获取读锁或写锁时,如果锁被占用,不会阻塞等待,而是立即返回结果,以便线程灵活处理。

4.2 读写锁非阻塞式上锁的使用场景

在一些需要快速响应,且读操作和写操作都不能长时间阻塞的场景中适用。比如在一个高速缓存系统中,线程需要快速判断能否获取锁来进行数据的读取或更新,而不是一直等待锁的释放。

4.3 读写锁非阻塞式上锁的使用方法

在 C++ 中,std::shared_mutex提供了try_lock_shared和try_lock方法来实现非阻塞式的读锁和写锁获取

#include <iostream>
#include <shared_mutex>
#include <thread>std::shared_mutex rwMutex;
int sharedData = 0;void tryRead() {if (rwMutex.try_lock_shared()) {std::cout << "Thread got read lock. Data: " << sharedData << std::endl;rwMutex.unlock_shared();} else {std::cout << "Thread couldn't get read lock." << std::endl;}
}void tryWrite() {if (rwMutex.try_lock()) {sharedData++;std::cout << "Thread got write lock. Data updated: " << sharedData << std::endl;rwMutex.unlock();} else {std::cout << "Thread couldn't get write lock." << std::endl;}
}int main() {std::thread readThreads[3];std::thread writeThread(tryWrite);for (int i = 0; i < 3; ++i) {readThreads[i] = std::thread(tryRead);}for (auto& th : readThreads) {th.join();}writeThread.join();return 0;
}

tryRead函数使用try_lock_shared尝试获取读锁,tryWrite函数使用try_lock尝试获取写锁,根据获取结果进行相应操作。

线程同步中的各类锁机制是 C++ 多线程编程的重要组成部分。互斥锁用于基本的线程同步,读写锁适用于读多写少的场景,非阻塞式锁则为需要快速响应的场景提供了解决方案。


http://www.ppmy.cn/devtools/160968.html

相关文章

ArcGIS Pro挖填方计算指南:全面解析与实施步骤

在工程实施之前&#xff0c;挖填方计算是确保项目成本控制、资源优化及地形合理利用的重要一环。ArcGIS Pro作为一款强大的地理信息系统软件&#xff0c;为工程师和规划者提供了高效的挖填方计算工具。本文将详细介绍如何在ArcGIS Pro中进行挖填方计算&#xff0c;涵盖从数据准…

Docker 在微服务架构中的应用(二)

五、最佳实践与注意事项 5.1 使用多阶段构建 多阶段构建是 Docker 17.05 版本引入的强大特性&#xff0c;它允许在一个 Dockerfile 中使用多个FROM指令&#xff0c;每个FROM指令定义一个独立的构建阶段。这一特性的主要优势在于优化最终生成的镜像大小&#xff0c;同时提高构…

Spring中的IOC详解

文章目录 IOC IOC容器的工作原理Bean的生命周期Bean的自动装配 AutowiredResourceInject 使用Spring底层组件 IOC Spring的核心之一是IOC&#xff0c;IOC全称为Inversion of Control&#xff0c;中文译为控制反转&#xff0c;是面向对象编程中的一种设计原则&#xff0c;可…

《算法基础入门:最常用的算法详解与应用(持续更新实战与面试题)》

1. 排序算法 排序算法是将一组数据按特定的顺序排列起来的算法&#xff0c;常见的有&#xff1a; 冒泡排序&#xff08;Bubble Sort&#xff09;选择排序&#xff08;Selection Sort&#xff09;插入排序&#xff08;Insertion Sort&#xff09;归并排序&#xff08;Merge So…

拆解微软CEO纳德拉战略蓝图:AI、量子计算、游戏革命如何改写未来规则!

2025年2月19日 知名博主Dwarkesh Patel对话微软CEO萨蒂亚纳德拉 在最新访谈释放重磅信号&#xff1a;AI将掀起工业革命级增长&#xff0c;量子计算突破引爆材料科学革命&#xff0c;游戏引擎进化为世界模拟器。 整个视频梳理出几大核心观点&#xff0c;揭示科技巨头的未来十年…

基于SpringBoot的智慧校园管理系统设计与实现的设计与实现(源码+SQL脚本+LW+部署讲解等)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

React 源码揭秘 | CompleteWork “归“的过程

上篇说了BeginWork的流程&#xff0c;我们继续看workLoop.ts/performUnitOfWork函数 /*** 处理单个fiber单元 包含 递&#xff0c;归 2个过程* param fiber*/ function performUnitOfWork(fiber: FiberNode) {// beginWork 递的过程const next beginWork(fiber, wipRootRende…

wps中zotero插件消失,解决每次都需要重新开问题

参考 查看zotero目录 D:\zotero\integration\word-for-windows 加载项点击 dotm即可 长期解决 把dom 复制到 C:\Users\89735\AppData\Roaming\kingsoft\office6\templates\wps\zh_CN还是每次都需要重新开的话 重新加载一下