Linux 之 【多线程】(STL、智能指针与线程安全、读者写者问题)
目录1.STL、智能指针与线程安全STL容器默认不是线程安全的智能指针线程安全2.读者写者问题背景读写锁核心特性321原则优先级策略POSIX读写锁接口读写锁示例设置写者优先示例1.STL、智能指针与线程安全STL容器默认不是线程安全的多线程环境下需要调用者自行保证线程安全常见方案使用外部锁如std::mutex保护容器操作智能指针线程安全1.unique_ptr独享所有权线程安全特性不涉及线程安全问题原因只在当前代码块范围内生效独占资源所有权不存在多个线程共享的情况2. shared_ptr共享所有权两部分需要区分对待组成部分线程安全性说明引用计数线程安全标准库基于原子操作(CAS)实现保证高效原子操作管理的资源不保证安全智能指针只负责管理资源生命周期不保护资源内容的并发访问关键理解引用计数的增减是原子操作多个线程同时操作shared_ptr不会导致计数错乱但通过shared_ptr访问的资源对象本身需要调用者自行加锁保护2.读者写者问题背景多读少写场景某些公共数据修改机会少但读取查找操作频繁且耗时。传统互斥锁会严重降低并发效率需要专门机制处理读写锁核心特性特性说明写独占写者加锁时其他读者和写者都不能访问读共享多个读者可以同时加锁读取数据优先级可设置读者优先或写者优先321原则维度内容说明3种关系写写互斥多个写者不能同时写写读互斥、同步写和读不能同时进行且需数据同步读读共享多个读者可以同时读2种角色读者、写者两类线程操作数据1个交易场所共享数据数据交换的内存区域优先级策略策略特点问题适用场景读者优先默认读者持续进入时写者被阻塞写者可能饥饿读极多、写可延迟写者优先写者到达后阻塞后续读者读者可能饥饿写操作需及时响应读者优先策略下只要存在任何读者正在读取数据后续到达的读者可以立即获得读锁继续读取而写者必须等待所有读者释放锁后才能写入。这种策略适合读操作极其频繁、写操作可以延迟的场景但可能导致写者饥饿——当读者持续不断地到来时写者可能永远无法获得写锁写者优先策略下一旦有写者到达并等待写锁后续新到达的读者将被阻塞不能插队读取直到等待的写者完成写入操作。这种策略确保写操作能及时执行适合需要数据及时更新的场景但可能造成读者饥饿——如果写者频繁出现读者可能长时间无法获取读锁。POSIX读写锁接口// 设置优先级 int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *attr, int pref); /* pref取值 PTHREAD_RWLOCK_PREFER_READER_NP - 读者优先默认 PTHREAD_RWLOCK_PREFER_WRITER_NP - 写者优先有BUG实际同读者优先 PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP - 写者优先写者不可递归 */ // 初始化和销毁 int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr); int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); // 加锁和解锁 int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); // 读锁 int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); // 写锁 int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); // 解锁读写锁示例#include stdio.h #include pthread.h #include unistd.h #include stdlib.h // 共享数据 int shared_data 0; // 读写锁 pthread_rwlock_t rwlock; // 读者线程 void* reader(void* arg) { int id *(int*)arg; while (1) { // 加读锁 pthread_rwlock_rdlock(rwlock); printf(读者 %d 读取数据: %d\n, id, shared_data); // 模拟读取耗时 usleep(100000); pthread_rwlock_unlock(rwlock); // 间隔一段时间再读 usleep(500000); } return NULL; } // 写者线程 void* writer(void* arg) { int id *(int*)arg; while (1) { // 加写锁 pthread_rwlock_wrlock(rwlock); shared_data; printf(写者 %d 修改数据为: %d\n, id, shared_data); // 模拟写入耗时 usleep(200000); pthread_rwlock_unlock(rwlock); // 间隔一段时间再写 usleep(2000000); } return NULL; } int main() { // 初始化读写锁默认读者优先 pthread_rwlock_init(rwlock, NULL); pthread_t readers[3], writers[2]; int reader_ids[3] {1, 2, 3}; int writer_ids[2] {1, 2}; // 创建3个读者线程 for (int i 0; i 3; i) { pthread_create(readers[i], NULL, reader, reader_ids[i]); } // 创建2个写者线程 for (int i 0; i 2; i) { pthread_create(writers[i], NULL, writer, writer_ids[i]); } // 运行一段时间后退出示例用sleep sleep(10); // 销毁读写锁 pthread_rwlock_destroy(rwlock); return 0; }设置写者优先示例#include stdio.h #include pthread.h #include unistd.h pthread_rwlock_t rwlock; int shared_counter 0; void* reader_func(void* arg) { int id *(int*)arg; for (int i 0; i 5; i) { pthread_rwlock_rdlock(rwlock); printf(读者 %d 读取: %d\n, id, shared_counter); usleep(50000); // 模拟读取 pthread_rwlock_unlock(rwlock); usleep(100000); } return NULL; } void* writer_func(void* arg) { int id *(int*)arg; for (int i 0; i 3; i) { pthread_rwlock_wrlock(rwlock); shared_counter; printf(写者 %d 写入: %d\n, id, shared_counter); usleep(100000); // 模拟写入 pthread_rwlock_unlock(rwlock); usleep(500000); } return NULL; } int main() { // 设置写者优先 pthread_rwlockattr_t attr; pthread_rwlockattr_init(attr); pthread_rwlockattr_setkind_np(attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); pthread_rwlock_init(rwlock, attr); pthread_t readers[5], writers[2]; int reader_ids[5] {1, 2, 3, 4, 5}; int writer_ids[2] {1, 2}; // 创建线程 for (int i 0; i 5; i) { pthread_create(readers[i], NULL, reader_func, reader_ids[i]); } for (int i 0; i 2; i) { pthread_create(writers[i], NULL, writer_func, writer_ids[i]); } // 等待线程结束 for (int i 0; i 5; i) { pthread_join(readers[i], NULL); } for (int i 0; i 2; i) { pthread_join(writers[i], NULL); } pthread_rwlock_destroy(rwlock); pthread_rwlockattr_destroy(attr); return 0; }

相关新闻

FastDDS是什么?如何进行源码编译?

FastDDS是什么?如何进行源码编译?

目录一、Ubuntu系统介绍二、FastDDS是什么三、FastDDS的源码编译四、FastDDS的简单测试一、Ubuntu系统介绍 Ubuntu是一个基于Linux的开源操作系统,由Canonical公司开发和维护。它以其易用性、稳定性和安全性而受到广泛赞誉。Ubuntu系统提供了一个图形化的桌面环境&…

2026/7/4 10:03:52 阅读更多 →
自定义类型:联合与枚举(二)

自定义类型:联合与枚举(二)

一、联合体大小的计算1.1.计算规则1.1.1联合的大小至少是最大成员的大小。1.1.2当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。1.2.联合的一个练习写一个程序:判断当前机器是大端还是小端?代码如下(…

2026/7/5 8:05:23 阅读更多 →
自定义类型:联合和枚举(一)

自定义类型:联合和枚举(一)

一、联合体1.1.联合体类型的说明像结构体一样,联合体也是由一个或者多个成员构成,这些成员可以是不同的类型。但是编译器只为最大的成员分配足够的内存空间,联合体的特点是所有成员共用一块内存空间所以联合体也叫做:共用体给联合…

2026/7/4 9:56:04 阅读更多 →

最新新闻

SeetaFace6实战:从零构建C# WinForm人脸多属性检测系统

SeetaFace6实战:从零构建C# WinForm人脸多属性检测系统

1. 环境准备与SDK集成在开始构建人脸多属性检测系统之前,我们需要准备好开发环境。首先确保你的Windows系统是64位版本(Win7及以上),并安装Visual Studio 2019或更高版本。我推荐使用.NET Framework 4.7.2以上版本,这是…

2026/7/6 12:53:38 阅读更多 →
免费文档下载神器:一键获取百度文库、道客巴巴等30+平台学习资料

免费文档下载神器:一键获取百度文库、道客巴巴等30+平台学习资料

免费文档下载神器:一键获取百度文库、道客巴巴等30平台学习资料 【免费下载链接】kill-doc 看到经常有小伙伴们需要下载一些免费文档,但是相关网站浏览体验不好各种广告,各种登录验证,需要很多步骤才能下载文档,该脚本…

2026/7/6 12:53:38 阅读更多 →
OpenCV 4.8 频域滤波实战:3步消除图像边缘效应与指纹环带分析

OpenCV 4.8 频域滤波实战:3步消除图像边缘效应与指纹环带分析

OpenCV频域滤波实战:消除边缘效应与指纹环带分析的三步法则频域滤波的核心挑战与解决方案当我们把图像从空间域转换到频域进行分析时,总会遇到两个典型问题:图像边缘突变导致的频谱干扰和特定纹理(如指纹)的环状频域特…

2026/7/6 12:51:36 阅读更多 →
OpenCV 4.8 图像频域分析实战:5种经典纹理频谱特征提取与可视化

OpenCV 4.8 图像频域分析实战:5种经典纹理频谱特征提取与可视化

OpenCV 4.8 图像频域分析实战:5种经典纹理频谱特征提取与可视化在数字图像处理领域,频域分析为我们打开了观察图像的全新视角。通过傅里叶变换,我们能够将图像从空间域转换到频率域,揭示隐藏在像素背后的周期性结构和纹理特征。本…

2026/7/6 12:51:36 阅读更多 →
DBNet 文本检测实战:基于PaddleOCR 2.7 从训练到部署的5个关键步骤

DBNet 文本检测实战:基于PaddleOCR 2.7 从训练到部署的5个关键步骤

DBNet文本检测实战:基于PaddleOCR 2.7的工业级落地指南当OCR技术遇上复杂多变的现实场景,传统文本检测方法往往在弯曲文本、密集排列或低对比度环境下表现乏力。DBNet(Differentiable Binarization)通过将二值化过程融入神经网络架…

2026/7/6 12:51:36 阅读更多 →
KMS_VL_ALL_AIO:3分钟搞定Windows和Office激活的智能工具箱

KMS_VL_ALL_AIO:3分钟搞定Windows和Office激活的智能工具箱

KMS_VL_ALL_AIO:3分钟搞定Windows和Office激活的智能工具箱 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 还在为Windows和Office激活烦恼吗?面对复杂的命令行工具不知所…

2026/7/6 12:51:36 阅读更多 →

日新闻

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2与MySQL单元测试兼容性:5个关键SQL语句差异与规避方案1. 单元测试中的数据库兼容性挑战在Java开发领域,单元测试是保证代码质量的重要环节。当应用涉及数据库操作时,测试环境的搭建往往成为开发者的痛点。H2数据库因其轻量级、内存模式和快…

2026/7/6 0:01:17 阅读更多 →
Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘 【免费下载链接】rbtray A fork of RBTray from http://sourceforge.net/p/rbtray/code/. 项目地址: https://gitcode.com/gh_mirrors/rb/rbtray 你是否厌倦了Windows任务栏上密密麻麻的图标&…

2026/7/6 0:01:17 阅读更多 →
Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C 运行时库一键安装终极指南:告别DLL缺失烦恼 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过这样的情况:下载了…

2026/7/6 0:05:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/6 8:11:50 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/6 8:11:52 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/6 6:52:56 阅读更多 →

月新闻