深入 C++ 线程库:从创建到同步的探索之旅
目录
创建多线程
获取线程返回值
1.传指针
2.传引用
原子操作
互斥量
互斥量(Mutex)的基本概念
mutex类型介绍
锁的类型
互斥锁(Mutex)
自旋锁(Spin Lock)
读写锁(Read - Write Lock)
互斥锁和自旋锁的区别
定义与工作原理
自旋锁(Spin Lock)
互斥锁(Mutex)
性能特性
自旋锁
互斥锁
适用场景
自旋锁
互斥锁
简单的使用示例
更好用的示例
一个更全面的例子
C++在<thread>中定义了C++线程库.
创建多线程
#include <iostream>
#include <thread>
using namespace std;
void show(int id, int count) { //线程函数for (int i = 0; i < count; ++i) {cout << "id:" << id << ",值:" << i << endl;}}
int main()
{thread t1(show, 1, 3);//创建线程对象t1thread t2(show, 2, 4);//创建线程对象t2t1.join();//必须使用join函数,否则线程结束会调用terminate()程序崩溃t2.join();//必须使用join函数,否则线程结束会调用terminate()程序崩溃cout << "main结束" << endl;return 0;
}
上面程序每次执行结果都不相同


获取线程返回值
如果需要获取线程的返回值,可以向线程传入一个保存结果的指针或者引用.不过这个一般不使用.
1.传指针
#include <iostream>
#include <thread>
using namespace std;
void show(int id,int count,int *v) {//线程函数for (int i = 0; i < count; ++i) {cout << "id:" << id << ",值:" << i << endl;*v += i;}}
int main() {int val1 = 0;//保存线程1返回值int val2 = 0;//保存线程2返回值thread t1(show, 1, 3,&val1);//创建线程对象t1thread t2(show, 2, 4,&val2);//创建线程对象t2t1.join();//必须使用join函数,否则线程结束会调用terminate()程序崩溃t2.join();//必须使用join函数,否则线程结束会调用terminate()程序崩溃cout << "val1=" << val1 << endl;cout << "val2=" << val2 << endl;cout << "main结束" << endl;return 0;
}

2.传引用
#include <iostream>
#include <thread>
using namespace std;
void show(int id,int count,int &v) {//线程函数for (int i = 0; i < count; ++i) {cout << "id:" << id << ",值:" << i << endl;v += i;}}
int main() {int val1 = 0;//保存线程1返回值int val2 = 0;//保存线程2返回值thread t1(show, 1, 3,ref(val1));//必须使用ref表明传递的引用thread t2(show, 2, 4,ref(val2)); t1.join();//必须使用join函数,否则线程结束会调用terminate()程序崩溃t2.join();//必须使用join函数,否则线程结束会调用terminate()程序崩溃cout << "val1=" << val1 << endl;cout << "val2=" << val2 << endl;cout << "main结束" << endl;return 0;
}

原子操作
下面的代码,不能实现想要的增加(val的结果是错误的).
#include <iostream>
#include <thread>
#include <vector>
using namespace std;
void increment(int& v)//对v进行增加操作
{for (int i = 0; i < 100000; i++)//这个次数少可能没有问题,因为电脑速度太快++v;
}int main()
{int val = 0;vector<thread>vec;//保存线程的容器for (int i = 0; i < 10; ++i)vec.push_back(thread(increment,ref(val)));for (auto& x : vec)x.join();cout << "val=" << val << endl;return 0;
}

原子类型允许原子访问,这意味着不需要额外的同步机制就可以执行并发的读写操作.
需要引用<atomic>
下面是把上面的代码加了原子操作
#include <iostream>
#include <thread>
#include <vector>
#include <atomic>//原子操作库
using namespace std;void increment(atomic<int>& v)//对v进行增加操作
{for (int i = 0; i < 100000; i++)++v;
}int main()
{atomic<int> val = 0;vector<thread>vec;//保存线程的容器for (int i = 0; i < 10; ++i)vec.push_back(thread(increment, ref(val)));for (auto& x : vec)x.join();cout << "val=" << val << endl;return 0;
}

互斥量
标准库<mutex>提供互斥量(也称互斥锁),它可以实现线程间的同步.
互斥量(Mutex)的基本概念
互斥量(互斥锁)是一种用于保护共享资源的同步原语。在多线程环境中,多个线程可能会同时访问和修改共享资源,这可能导致数据竞争(Data Race),即多个线程在没有适当同步的情况下同时读写同一块内存区域,从而导致程序出现未定义行为。互斥量通过提供互斥访问的机制来解决这个问题,它确保在同一时刻只有一个线程能够访问被保护的共享资源。
原语通常指的是在操作系统、数据库或并发编程等领域中,由若干条指令组成的、用于完成一定功能的一个过程或操作。这些原语通常是不可分割的,即执行过程中不允许被中断,以保证操作的原子性和正确性。
mutex类型介绍
在 C++ 标准库中,mutex是最基本也是使用最多的互斥量类型。它提供了lock和unlock两个基本成员函数。
- lock函数:获取互斥量的锁,从而可以访问被保护的共享资源。如果互斥量已经被其他线程锁定,那么调用lock函数的线程将会阻塞,直到互斥量被解锁。
- unlock函数:当一个线程完成对共享资源的访问后,需要调用unlock函数来释放互斥量的锁,这样其他等待的线程才有机会获取锁并访问共享资源。
注意:这两个函数不建议直接使用,容易出现死锁.可使用后面的方式.
mutex有可以分为两大类非定时互斥量和定时互斥量(增加一个超时放弃属性).其中非定时包括mutex,recursive_mutex(递归的),shared_mutex,定时包括timed_mutex,recursive_timed_mutex,shared_timed_mutex.
锁的类型
互斥锁(Mutex)
原理:互斥锁是最常见的一种锁,用于保护共享资源。它的核心原理是在同一时刻只允许一个线程访问被保护的资源。当一个线程获取了互斥锁后,其他线程如果想要访问该资源,就必须等待锁被释放。互斥锁通过阻塞其他线程来实现对共享资源的独占访问。
自旋锁(Spin Lock)
原理:自旋锁在获取锁时,如果锁已被占用,线程不会阻塞,而是在一个循环中不断地检查锁是否可用。它是基于原子操作实现的,通过循环等待的方式来获取锁。
读写锁(Read - Write Lock)
原理:读写锁允许同时有多个线程对共享资源进行读操作,但在有线程进行写操作时,其他线程(无论是读还是写)都必须等待。读写锁的状态通常分为读模式和写模式。当一个线程以读模式获取锁后,其他线程仍然可以以读模式获取锁,但不能以写模式获取锁;当一个线程以写模式获取锁后,其他线程都不能获取锁。
互斥锁和自旋锁的区别
定义与工作原理
自旋锁(Spin Lock)
- 定义:自旋锁是一种轻量级锁机制。
- 工作原理:当线程尝试获取一个已被占用的自旋锁时,它不会立即放弃CPU,而是原地循环(自旋),不断检查锁的状态,直到锁变为可用。这种机制避免了上下文切换的开销,但如果等待时间较长,会持续占用CPU资源。(类似食堂打快餐排队)
互斥锁(Mutex)
- 定义:互斥锁是最常用的线程间同步机制,具有互斥性和互锁性。
- 工作原理:当一个线程试图锁定一个已经被其他线程持有的互斥锁时,该线程会被操作系统挂起(进入睡眠状态),并从运行队列中移除,直到锁被释放,操作系统才会唤醒该线程,将其放回运行队列。这个过程涉及上下文切换,有一定的系统开销。(类似食堂吃麻辣烫拿号码牌排队)
性能特性
自旋锁
- 优点:在等待时间较短时,可以避免上下文切换的开销,提高效率。
- 缺点:如果等待时间较长,持续占用CPU的自旋会成为性能瓶颈,浪费CPU资源。
互斥锁
- 优点:在锁等待时间较长时,可以让出CPU资源,避免资源浪费。
- 缺点:在获取锁失败时会引入较高的上下文切换开销。此外,互斥锁还可能导致优先级反转问题,即高优先级线程可能因等待低优先级线程释放锁而被延迟。
适用场景
自旋锁
- 适用于锁的持有时间很短,以及CPU核心较少的环境。因为自旋会占用CPU,如果锁的等待时间过长,会浪费CPU资源,降低整体效率。
- 通常用于内核空间,特别是中断处理程序中,因为在中断上下文中不能休眠。
互斥锁
- 适用于锁的持有时间不确定或可能较长的情况。由于它会导致线程阻塞,适用于用户态程序和不需要高响应速度的场合。
简单的使用示例
以下是一个简单的示例,展示了如何使用std::mutex来保护共享资源: 警告:这是一个简单,但并不好的例子,不要去调用lock和unlock函数,容易出现死锁.后面有更好的方式.
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
using namespace std;mutex mtx;//互斥锁对象void increment(int& v)//对v进行增加操作
{for (int i = 0; i < 100000; i++){mtx.lock();//加锁++v;mtx.unlock();//开锁}
}int main()
{int val = 0;vector<thread>vec;//保存线程的容器for (int i = 0; i < 10; ++i)vec.push_back(thread(increment, ref(val)));for (auto& x : vec)x.join();cout << "val=" << val << endl;return 0;
}

更好用的示例
unique_lock是 C++ 标准库中用于管理互斥量(mutex)的模板类,它的析构函数会自动释放所关联的互斥量.
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
using namespace std;mutex mtx;//互斥锁对象void increment(int& v)//对v进行增加操作
{for (int i = 0; i < 100000; i++){unique_lock<mutex> lock(mtx);//自动加锁,生命周期结束后自动解锁++v;}
}int main()
{int val = 0;vector<thread>vec;//保存线程的容器for (int i = 0; i < 10; ++i)vec.push_back(thread(increment, ref(val)));for (auto& x : vec)x.join();cout << "val=" << val << endl;return 0;
}

一个更全面的例子
顺序执行每个线程5次.
#include <iostream>
#include <thread>
#include <string>
#include <mutex>
#include <condition_variable>
using namespace std;mutex mtx; //互斥量
condition_variable cv;//条件变量
int current_thread = 1; // 当前需要执行的线程编号//线程编号和输出的信息
void print(int thread_id, const string& message) {for (int i = 0; i < 5; ++i) { // 每个线程打印5次unique_lock<mutex> lock(mtx);//加锁//阻塞,直到条件为真cv.wait(lock, [&]() { return current_thread == thread_id; }); // 等待当前线程是指定线程cout << message << endl;//打印相应数据current_thread = thread_id % 3 + 1; // 切换到下一个线程(1 -> 2 -> 3)cv.notify_all(); // 唤醒其他线程}
}int main() {thread t1(print, 1, "Thread 1");//创建线程1thread t2(print, 2, "Thread 2");//创建线程2thread t3(print, 3, "Thread 3");//创建线程3t1.join();t2.join();t3.join();return 0;
}

相关文章:
深入 C++ 线程库:从创建到同步的探索之旅
目录 创建多线程 获取线程返回值 1.传指针 2.传引用 原子操作 互斥量 互斥量(Mutex)的基本概念 mutex类型介绍 锁的类型 互斥锁(Mutex) 自旋锁(Spin Lock) 读写锁(Read - Write Lo…...
【2025年认证杯数学中国数学建模网络挑战赛】A题 解题建模过程与模型代码(基于matlab)
目录 【2025年认证杯数学建模挑战赛】A题解题建模过程与模型代码(基于matlab)A题 小行星轨迹预测解题思路第一问模型与求解第二问模型与求解 【2025年认证杯数学建模挑战赛】A题 解题建模过程与模型代码(基于matlab) A题 小行星轨…...
Rust重定义数据库内核:从内存安全到性能革命的破界之路
Rust语言正在颠覆传统数据库开发范式,其独特的所有权系统与零成本抽象能力,为攻克C/C时代遗留的内存泄漏、并发缺陷等顽疾提供全新解决方案。本文通过TiKV、Materialize等新一代数据库核心组件的实践案例,剖析Rust如何重塑存储引擎、查询优化…...
大模型在慢性髓细胞白血病(CML)初治成人患者诊疗中的应用研究
目录 一、引言 1.1 研究背景与意义 1.2 国内外研究现状 1.3 研究目的与内容 二、大模型技术与 CML 相关知识 2.1 大模型技术原理与特点 2.2 CML 的病理生理与诊疗现状 三、术前风险预测与手术方案制定 3.1 术前数据收集与预处理 3.2 大模型预测术前风险 3.3 根据预测…...
Matlab 分数阶PID控制永磁同步电机
1、内容简介 Matlab 203-分数阶PID控制永磁同步电机 可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 4、参考论文 略...
GO语言入门-反射5(结构体的Tag)
12.5 结构体的 Tag 在定义结构体类型时,可以在字段后面加上一个字符串,称为 Struct Tag。Tag 主要用来补充附加信息。 Tag 由多个 key - value 构成,并以空格来分隔,key 和 value 之间用英文的冒号分隔。其格式如下:…...
免费下载 | 2025电力数据资产管理体系白皮书
本文是一份关于2025年电力数据资产管理体系的白皮书,详细阐述了电力数据要素和数据资产管理的现状、挑战、发展进程以及电网数据资产管理体系的构建与实践。白皮书强调了数据作为生产要素的重要性,并提出了电网数据资产管理体系的创新模式,旨…...
4185 费马小定理求逆元
4185 费马小定理求逆元 ⭐️难度:简单 🌟考点:费马小定理 📖 📚 import java.util.Scanner; import java.util.Arrays;public class Main {static int[][] a;public static void main(String[] args) {Scanner sc …...
处理Excel表不等长时间序列用tsfresh提取时序特征
我原本的时间序列格式是excel表记录的,每一行是一条时间序列,时间序列不等长。 要把excel表数据读取出来之后转换成extract_features需要的格式。 1.读取excel表数据 import pandas as pd import numpy as np from tsfresh import extract_features mda…...
从keys到SCAN:Redis批量删除的进化之路
标签:Redis、批量删除、前缀匹配、性能优化 一、痛点分析:为什么需要批量删除指定前缀的键? 在 Redis 使用过程中,我们经常会遇到这样的场景: 需要对某一类数据进行清理,例如用户会话、缓存数据等,而这些数据通常以某种前缀命名(如 user:session:*、cache:data:*)。如…...
界面控件DevExpress WinForms v25.1新功能预览 - 聚焦用户体验升级
DevExpress WinForms拥有180组件和UI库,能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜…...
卷积神经网络(CNN)基础
目录 一、应用场景 二、卷积神经网络的结构 1. 输入层(Input Layer) 2. 卷积层(Convolutional Layer) 3. 池化层(Pooling Layer) 最大池化(max_pooling)或平均池化(…...
Android Spotify-v9.0.36.443-arm64-Experimental Merged版
Android Spotify 链接:https://pan.xunlei.com/s/VONXTdIv9d4FnAiNMMliIAEJA1?pwdxt7q# Android Spotify-v9.0.36.443-arm64-Experimental Merged版 享受高达256kbps的AAC音频。...
html元素转图像之深入探索 html - to - image:功能、应用与实践
html元素转图像之深入探索 html-to-image:功能、应用与实践 一、引言 使用该插件 需要注意页面上的图片都能正常显示,否则会报错,或生成的图片有误,注意注意。 在当今数字化内容丰富多样的时代,将网页上的特定 HTML…...
LLM之Agent(十六)| MCP已“过时”?Google近期推出Agent2Agent 协议 (A2A)
如今,企业越来越多地构建和部署自主代理,以帮助扩展、自动化和增强整个工作场所的流程 - 从订购新笔记本电脑到协助客户服务代表,再到协助供应链规划。 为了最大限度地发挥代理 AI 的优势,这些代理能够在一个动态的、多代理的生态…...
Transformer 训练:AutoModelForCausalLM,AutoModelForSequenceClassification
Transformer 训练:AutoModelForCausalLM,AutoModelForSequenceClassification 目录 Transformer 训练:AutoModelForCausalLM,AutoModelForSequenceClassification`AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)`功能概述参数解释`AutoModelForSequen…...
网络安全1
一、网络安全的定义与重要性 定义 网络安全(信息技术安全):保护计算机系统和网络免受电子攻击的技术和过程,包括保护个人信息和企业数据不被盗窃、破坏或非法访问。涵盖范围:网络设备、数据传输、系统运行安全。 重要…...
Java学习总结-端口-协议
端口号:一个16位的二进制,范围是0-65535 端口分类: 周知端口:0-1023,被预先定义的知名应用占用(如:HTTP占用80,FTP占用21) 注册端口:1024-49151࿰…...
克魔助手(Kemob)安装与注册完整教程 - Windows/macOS双平台指南
iOS设备管理工具克魔助手便携版使用全指南 前言:为什么需要专业的iOS管理工具 在iOS开发和设备管理过程中,开发者经常需要突破系统限制,实现更深层次的控制和调试。本文将详细介绍一款实用的便携式工具的使用方法,帮助开发者快速…...
✅ Ultralytics YOLO 训练(Train)时实时获取 COCO 指标(AP):2025最新配置与代码详解 (小白友好 + B站视频)
✅ YOLO获取COCO指标(4): 训练(Train)启用COCO API评估(实时监控AP指标)| 发论文必看! | Ultralytics | 小白友好 文章目录 一、问题定位二、原理分析三、解决方案与实践案例步骤 1: 在 model.train() 调用中设置 save_jsonTrue步骤 2: 修改 …...
qwen-vl 实现OCR的测试
OCR 技术是数字化时代必不可少的实用工具。以前都依赖专业的公司的专业软件才能完成。成本很高。也正因为如此,我国纸质资料的数字化并不普及。基于大模型的ORC 也许会改变这样的现状。 文本识别,也称为光学字符识别 (OCR),可以将印刷文本或…...
算法训练之动态规划(五)——简单多状态问题
♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…...
C++ 大数相加(简要版)
#include <algorithm> #include <iterator> class Solution { public:/*** 计算两个数之和* param s string字符串 表示第一个整数* param t string字符串 表示第二个整数* return string字符串*/string solve(string s, string t) {// 处理空字符串的情况…...
SVMSPro分布式综合安防管理平台-->以S3存储革新,开启智能安防新纪元
SVMSPro分布式综合安防管理平台–>以S3存储革新,开启智能安防新纪元 在数字化转型浪潮下,企业安防管理正面临海量数据存储、跨区域协同以及数据安全的严峻挑战。如何实现高效、弹性、低成本的存储扩容?如何确保关键录像数据万无一失&…...
KV Cache大模型推理加速功能
KV Cache KV Cache是大模型标配的推理加速功能,也是推理过程中,显存资源巨大开销的元凶之一。在模型推理时,KV Cache在显存占用量可达30%以上。 目前大部分针对KV Cache的优化工作,主要集中在工程上。比如著名的VLLM,…...
速盾:高防CDN节点对收录有影响吗?
引言 搜索引擎收录是网站运营中至关重要的环节,它直接影响着网站的曝光度和流量。近年来,随着网络安全威胁的增加,许多企业开始采用高防CDN(内容分发网络)来保护其网站免受DDoS攻击和其他形式的网络攻击。然而&#x…...
脑科学与人工智能的交叉:未来智能科技的前沿与机遇
引言 随着科技的迅猛发展,脑科学与人工智能(AI)这两个看似独立的领域正在发生深刻的交汇。脑机接口、神经网络模型、智能机器人等前沿技术,正带来一场跨学科的革命。这种结合不仅推动了科技进步,也在医疗、教育、娱乐等…...
Linux 系统中从源码编译安装软件
以下是 Linux 系统中 从源码编译安装软件 的详细步骤和注意事项,帮助你掌握这一高级操作技能: 一、编译安装的核心流程 1. 下载源码包(通常为 .tar.gz/.tar.bz2/.tar.xz) 2. 解压源码包 3. 进入源码目录 4. 配置编译参数…...
docker 运行自定义化的服务-后端
docker 运行自定义化的服务-前端-CSDN博客 运行自定义化的后端服务 具体如下: ①打包后端项目,形成jar包 ②编写dockerfile文件,文件内容如下: # 使用官方 OpenJDK 镜像 FROM jdk8:1.8LABEL maintainer"ATB" version&…...
基于关键字定位的自动化PDF合同拆分
需求背景: 问题描述: 我有一份包含多份合同的PDF文件,需要将这些合同分开并进行解析。 传统方法(如以固定页数作为分割点)不够灵活,无法满足需求。 现有方法的不足: 网上找到的工具大多依赖手动…...
