第16天:C++多线程完全指南 - 从基础到现代并发编程
第16天:C++多线程完全指南 - 从基础到现代并发编程
一、多线程基础概念
1. 线程创建与管理(C++11)
#include <iostream>
#include <thread>void hello() {std::cout << "Hello from thread " << std::this_thread::get_id() << "\n";
}int main() {std::thread t1(hello);std::thread t2([](){std::cout << "Lambda thread running\n";});t1.join(); // 等待线程完成t2.join();// 输出可能交错:// Hello from thread 140245230233344// Lambda thread running
}
2. 并发与并行区别
- 并发:交替处理多个任务(单核)
- 并行:同时处理多个任务(多核)
// 查看硬件支持线程数
unsigned int n = std::thread::hardware_concurrency();
std::cout << n << " concurrent threads supported\n";
二、线程同步核心机制
1. 互斥锁(mutex)与RAII
#include <mutex>std::mutex mtx;
int shared_data = 0;void safe_increment() {std::lock_guard<std::mutex> lock(mtx); // 自动释放锁++shared_data; // 临界区操作
}int main() {std::thread threads[10];for (auto& t : threads) {t = std::thread(safe_increment);}for (auto& t : threads) {t.join();}std::cout << "Final value: " << shared_data; // 正确输出10
}
2. 条件变量(生产者-消费者模式)
#include <queue>
#include <condition_variable>std::mutex mtx;
std::condition_variable cv;
std::queue<int> data_queue;void producer() {for (int i=0; i<5; ++i) {{std::lock_guard<std::mutex> lock(mtx);data_queue.push(i);}cv.notify_one(); // 通知消费者std::this_thread::sleep_for(std::chrono::milliseconds(100));}
}void consumer() {while(true) {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, []{ return !data_queue.empty(); });int data = data_queue.front();data_queue.pop();lock.unlock();std::cout << "Consumed: " << data << "\n";if(data == 4) break;}
}
三、现代C++并发特性
1. 异步任务(std::async)
#include <future>int compute(int x) {return x * x;
}int main() {auto future = std::async(std::launch::async, compute, 12);std::cout << "Result: " << future.get(); // 输出144
}
2. 原子操作(std::atomic)
#include <atomic>std::atomic<int> counter(0); // 无需锁的线程安全计数器void increment() {for (int i=0; i<100000; ++i) {++counter; // 原子操作}
}// 测试:两个线程同时递增
// 最终结果正确为200000
四、线程安全设计模式
1. 线程局部存储(thread_local)
thread_local int tls_var = 0; // 每个线程独立副本void thread_func() {++tls_var;std::cout << "Thread " << std::this_thread::get_id() << ": " << tls_var << "\n";
}// 每个线程输出自己的递增结果
2. 线程池实现(C++17)
#include <vector>
#include <functional>
#include <queue>class ThreadPool {std::vector<std::thread> workers;std::queue<std::function<void()>> tasks;std::mutex queue_mutex;std::condition_variable condition;bool stop = false;public:ThreadPool(size_t threads) {for(size_t i=0; i<threads; ++i) {workers.emplace_back([this]{while(true) {std::function<void()> task;{std::unique_lock<std::mutex> lock(queue_mutex);condition.wait(lock, [this]{ return stop || !tasks.empty(); });if(stop && tasks.empty()) return;task = std::move(tasks.front());tasks.pop();}task();}});}}template<class F>void enqueue(F&& f) {{std::lock_guard<std::mutex> lock(queue_mutex);tasks.emplace(std::forward<F>(f));}condition.notify_one();}~ThreadPool() {{std::lock_guard<std::mutex> lock(queue_mutex);stop = true;}condition.notify_all();for(auto& worker : workers)worker.join();}
};
五、并发编程陷阱与调试
1. 死锁检测示例
std::mutex m1, m2;void thread_A() {std::lock_guard<std::mutex> lock1(m1);std::this_thread::sleep_for(std::chrono::milliseconds(100));std::lock_guard<std::mutex> lock2(m2); // 可能死锁点
}void thread_B() {std::lock_guard<std::mutex> lock2(m2);std::this_thread::sleep_for(std::chrono::milliseconds(100));std::lock_guard<std::mutex> lock1(m1); // 可能死锁点
}// 解决方案:使用std::lock同时锁定多个互斥量
void safe_lock() {std::lock(m1, m2);std::lock_guard<std::mutex> lock1(m1, std::adopt_lock);std::lock_guard<std::mutex> lock2(m2, std::adopt_lock);
}
六、现代C++并发增强
1. C++20信号量(semaphore)
#include <semaphore>std::counting_semaphore<5> sem(3); // 允许3个同时访问void limited_thread() {sem.acquire();// 访问受限资源sem.release();
}
2. 屏障(C++20 barrier)
std::barrier sync_point(3); // 等待3个线程到达void worker() {// Phase 1sync_point.arrive_and_wait();// Phase 2(所有线程完成Phase1后继续)
}
七、常见问题解答
Q:如何检测数据竞争?
- 使用ThreadSanitizer编译:
g++ -fsanitize=thread -g -O1 program.cpp
- 示例输出:
WARNING: ThreadSanitizer: data race
Q:std::mutex和std::shared_mutex区别?
- std::mutex:独占锁
- std::shared_mutex:读写锁(C++17)
std::shared_mutex smtx;// 写操作使用独占锁
{std::unique_lock lock(smtx);data = new_value;
}// 读操作使用共享锁
{std::shared_lock lock(smtx);read_data = data;
}
八、今日总结
✅ 核心掌握:
- 🧵 线程生命周期管理(创建、等待、分离)
- 🔒 同步原语使用场景(mutex/atomic/condition_variable)
- 🚧 典型并发问题检测与预防(死锁、数据竞争)
相关文章:
第16天:C++多线程完全指南 - 从基础到现代并发编程
第16天:C多线程完全指南 - 从基础到现代并发编程 一、多线程基础概念 1. 线程创建与管理(C11) #include <iostream> #include <thread>void hello() {std::cout << "Hello from thread " << std::this_…...
中科大计算机网络原理 1.5 Internt结构和ISP
一、互联网的层次化架构 覆盖范围分层 主干网(Tier-1级) 国家级或行业级核心网络,承担跨区域数据传输和全球互联功能。例如中国的四大主干网(ChinaNET、CERNET等)以及跨国运营商(如AT&T、Deuts…...
Windows安装sql server2017
看了下官网的文档,似乎只有ubuntu18.04可以安装,其他debian系的都不行,还有通过docker的方式安装的。 双击进入下载的ISO,点击执行可执行文件,并选择“是” 不要勾选 警告而已,不必理会 至少勾选这两…...
计算机网络之传输层(tcp协议)
一、TCP协议的特点 面向连接:TCP使用面向连接的通信模式,通信双方需要先建立连接,然后才能进行数据的传输。连接建立过程采用三次握手的方式。 可靠性:TCP提供可靠的数据传输服务,确保数据的完整性、有序性和正确性。…...
从零到一:如何用阿里云百炼和火山引擎搭建专属 AI 助手(DeepSeek)?
本文首发:从零到一:如何用阿里云百炼和火山引擎搭建专属 AI 助手(DeepSeek)? 阿里云百炼和火山引擎都推出了免费的 DeepSeek 模型体验额度,今天我和大家一起搭建一个本地的专属 AI 助手。 阿里云百炼为 …...
Open3D解决SceneWidget加入布局中消失的问题
Open3D解决SceneWidget加入布局中消失的问题 Open3D解决SceneWidget加入布局中消失的问题1. 问题2. 问题代码3. 解决 Open3D解决SceneWidget加入布局中消失的问题 1. 问题 把SceneWidget加到布局管理其中图形可以展示出来,但是鼠标点击就消失了。 stackoverflow上已…...
计算机毕业设计Python+DeepSeek-R1大模型游戏推荐系统 Steam游戏推荐系统 游戏可视化 游戏数据分析(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
Linux笔记---缓冲区
1. 什么是缓冲区 在计算机系统中,缓冲区(Buffer) 是一种临时存储数据的区域,主要用于协调不同速度或不同时序的组件之间的数据传输,以提高效率并减少资源冲突。它是系统设计中的重要概念,尤其在I/O操作、网…...
如何流畅访问github
1.传输数据原理 本地计算机通过本地网接入运营骨干网,经过DNS域名解析,将输入的字符解析为要连接的真实IP地址,服务器返还一个数据包(github)给计算机 2.原因 DNS域名污染-DNS解析出现问题,导致访问一个不存在的服务器 3.解决…...
java基础+面向对象
Java基础语法 CMD命令 cls 清屏 cd 目录进入文件 cd… 退回 dir 查看当前目录所有文件 E:进入E盘 exit 退出 环境变量就是不用去专门的盘符去找,直接去环境变量里找到文件 语言优势 编译型语言c: 整体翻译 解释型语言python&#x…...
Linux 检测内存泄漏方法总结
文章目录 strace检测asan内存检测linux下gperf工具(tcmalloc)检查C/C代码内存泄露问题参考 strace检测 (1)启动程序 (2) strace -f -p <PID> -tt -e brk,mmap,mmap2,munmapbrk 变大 → 说明堆增长…...
本地部署deepseek大模型后使用c# winform调用(可离线)
介于最近deepseek的大火,我就在想能不能用winform也玩一玩本地部署,于是经过查阅资料,然后了解到ollama部署deepseek,最后用ollama sharp NUGet包来实现winform调用ollama 部署的deepseek。 本项目使用Vs2022和.net 8.0开发,ollam…...
Python----数据分析(Numpy:安装,数组创建,切片和索引,数组的属性,数据类型,数组形状,数组的运算,基本函数)
一、 Numpy库简介 1.1、概念 NumPy(Numerical Python)是一个开源的Python科学计算库,旨在为Python提供 高性能的多维数组对象和一系列工具。NumPy数组是Python数据分析的基础,许多 其他的数据处理库(如Pandas、SciPy)都依赖于Num…...
Leetcode-最大矩形(单调栈)
一、题目描述 给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。 输入:matrix [["1","0","1","0","0"],["1","0&…...
域内委派维权
为某个服务账户配置 krbtgt 用户的非约束性委派或基于资源的约束性委派。这里我的 krbtgt 的基于资源约束性委派我利用不了,所以使用的是域控的机器账户 dc01$ 进行维权。 抓取所有 hash。 mimikatz.exe "privilege::debug" "lsadump::dcsync /doma…...
leetcode---LCR 140.训练计划
给定一个头节点为 head 的链表用于记录一系列核心肌群训练项目编号,请查找并返回倒数第 cnt 个训练项目编号。 示例 1: 输入:head [2,4,7,8], cnt 1 输出:8 提示: 1 < head.length < 1000 < head[i] <…...
Linux基础 -- ARM 32位常用机器码(指令)整理
ARM 32位常用机器码(指令)整理 1. 数据处理指令(运算、逻辑、比较) 指令含义示例备注MOV赋值(寄存器传输)MOV R0, R1直接将 R1 复制到 R0MVN取反MVN R0, R1R0 ~R1ADD加法ADD R0, R1, R2R0 R1 R2ADC带进…...
内存中的缓存区
在 Java 的 I/O 流设计中,BufferedInputStream 和 BufferedOutputStream 的“缓冲区”是 内存中的缓存区(具体是 JVM 堆内存的一部分),但它们的作用是优化数据的传输效率,并不是直接操作硬盘和内存之间的缓存。以下是详…...
基于 Spring Boot 的 +Vue“宠物咖啡馆平台” 系统的设计与实现
大家好,今天要和大家聊的是一款基于 Spring Boot 的 “宠物咖啡馆平台” 系统的设计与实现。项目源码以及部署相关事宜请联系我,文末附上联系方式。 项目简介 基于 Spring Boot 的 “宠物咖啡馆平台” 系统设计与实现的主要使用者分为 管理员、用户 和…...
LeetCode 解题思路 7(Hot 100)
解题思路: 初始化窗口元素: 遍历前 k 个元素,构建初始单调队列。若当前索引对应值大于等于队尾索引对应值,移除队尾索引,将当前索引加入队尾。遍历结束时当前队头索引即为当前窗口最大值,将其存入结果数组…...
龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...
OCR MLLM Evaluation
为什么需要评测体系?——背景与矛盾 能干的事: 看清楚发票、身份证上的字(准确率>90%),速度飞快(眨眼间完成)。干不了的事: 碰到复杂表格(合并单元…...
向量几何的二元性:叉乘模长与内积投影的深层联系
在数学与物理的空间世界中,向量运算构成了理解几何结构的基石。叉乘(外积)与点积(内积)作为向量代数的两大支柱,表面上呈现出截然不同的几何意义与代数形式,却在深层次上揭示了向量间相互作用的…...
