C++ 之多线程相关总结
C++ 之多线程相关总结
1.多线程相关基础知识
1.1 线程的创建和管理
1. std::thread 类:
用于创建和管理线程。通过将可调用对象(如函数、函数对象、lambda 表达式)作为参数传递给 std::thread 的构造函数,可以创建一个新的线程。
join()方法会阻塞当前线程,直到被调用的线程执行完毕。如果不调用join()或detach(),程序会在std::thread对象析构时终止程序,因为会调用std::terminate()。detach()方法允许线程独立运行,与主线程分离,不再被std::thread对象管理,它会继续在后台执行直至完成或程序结束。
#include <iostream>
#include <thread>void threadFunction() {std::cout << "Thread function running." << std::endl;
}int main() {std::thread t(threadFunction); // 创建一个新的线程,执行 threadFunctiont.join(); // 等待线程结束return 0;
}
2. 线程函数:
可以是普通函数、成员函数、函数对象或 lambda 表达式。
#include <iostream>
#include <thread>class MyClass {
public:void memberFunction() {std::cout << "Member function running in thread." << std::endl;}
};int main() {MyClass obj;std::thread t(&MyClass::memberFunction, &obj); // 调用成员函数t.join();return 0;
}
1.2 线程同步
1.互斥量(Mutex):
- std::mutex 提供了基本的互斥机制,用于保护共享数据,防止多个线程同时访问。
#include <iostream>
#include <thread>
#include <mutex>std::mutex mtx;void printMessage(const std::string& message) {std::lock_guard<std::mutex> lock(mtx); // 自动加锁和解锁std::cout << message << std::endl;
}int main() {std::thread t1(printMessage, "Hello from thread 1");std::thread t2(printMessage, "Hello from thread 2");t1.join();t2.join();return 0;
}
std::lock_guard是一个 RAII 类,在构造时自动锁定互斥量,在析构时自动解锁,确保正确的锁定和解锁操作。std::unique_lock提供了更灵活的锁定方式,可以手动加锁、解锁,支持延迟锁定和所有权转移。
2.条件变量(Condition Variables):
- std::condition_variable 允许线程等待某些条件的发生。
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>std::mutex mtx;
std::condition_variable cv;
std::queue<int> dataQueue;void producer() {for (int i = 0; i < 10; ++i) {std::this_thread::sleep_for(std::chrono::milliseconds(100));std::unique_lock<std::mutex> lock(mtx);dataQueue.push(i);std::cout << "Produced: " << i << std::endl;cv.notify_one(); // 通知一个等待的线程}
}void consumer() {while (true) {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, []{ return!dataQueue.empty(); }); // 等待条件满足int data = dataQueue.front();dataQueue.pop();lock.unlock();std::cout << "Consumed: " << data << std::endl;if (data == 9) break;}
}int main() {std::thread t1(producer);std::thread t2(consumer);t1.join();t2.join();return 0;
}
cv.wait()会释放锁并等待条件变量被通知,一旦收到通知,它会重新获取锁。
3. 原子操作
std::atomic模板类提供了原子操作,确保操作的不可分割性,避免数据竞争。
#include <iostream>
#include <thread>
#include <atomic>std::atomic<int> counter(0);void increment() {for (int i = 0; i < 1000; ++i) {++counter;}
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();std::cout << "Counter value: " << counter << std::endl;return 0;
}
1.3 线程间通信
1.共享数据:
- 多个线程可以通过共享数据进行通信,但需要使用互斥量或其他同步机制来保护数据。
- 避免死锁,如避免多个线程以不同顺序获取多个锁。
2.消息传递:
- 使用
std::promise和std::future可以实现线程间的单向消息传递。
#include <iostream>
#include <thread>
#include <future>int factorial(int n) {int result = 1;for (int i = 1; i <= n; ++i) {result *= i;}return result;
}int main() {std::promise<int> prom;std::future<int> fut = prom.get_future();std::thread t([&prom]() {int result = factorial(5);prom.set_value(result);});std::cout << "Factorial result: " << fut.get() << std::endl;t.join();return 0;
}
1.4 高级线程工具
1. std::async 和 std::future:
std::async可以异步执行函数,并返回一个std::future对象。
#include <iostream>
#include <future>int add(int a, int b) {return a + b;
}int main() {std::future<int> result = std::async(std::launch::async, add, 3, 4);std::cout << "Sum: " << result.get() << std::endl;return 0;
}
std::launch::async表示函数会在另一个线程中立即执行,std::launch::deferred表示延迟执行,直到调用get()时才在调用线程中执行。
2. std::packaged_task:
- 包装可调用对象,允许将其作为任务传递,并通过
std::future获取结果。
#include <iostream>
#include <thread>
#include <future>int main() {std::packaged_task<int(int, int)> task(add);std::future<int> result = task.get_future();std::thread t(std::move(task), 3, 4);std::cout << "Sum: " << result.get() << std::endl;t.join();return 0;
}
2. 线程的使用:创建及管理
1.类内创建线程
- 可以通过成员函数或者析构函数初始化或者创建线程,通过析构函数关闭/销毁线程
#include <iostream>
#include <thread>
#include <atomic>
#include <chrono>class ThreadedClass {
private:std::thread workerThread;std::atomic<bool> stopFlag;// 线程函数void workerFunction() {while (!stopFlag) {std::cout << "Thread is running..." << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));}std::cout << "Thread is stopping..." << std::endl;}
public:ThreadedClass() : stopFlag(false) {// 启动线程workerThread = std::thread(&ThreadedClass::workerFunction, this);}~ThreadedClass() {// 设置停止标志stopFlag = true;if (workerThread.joinable()) {// 等待线程结束workerThread.join();}}
};int main() {ThreadedClass obj;// 让程序运行一段时间,以便观察线程的行为std::this_thread::sleep_for(std::chrono::seconds(5));return 0;
}
2. 函数内部创建线程
- 单独执行某个函数或者某个类的成员函数
#include <iostream>
#include <thread>
#include <chrono>class MyClass {
public:// 类中的函数,将在新线程中执行void classFunction() {for (int i = 0; i < 5; ++i) {std::cout << "Class function running, iteration: " << i << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));}}
};// 主函数,在其中创建线程执行类的函数
void mainFunction() {std::cout << "Main function starts." << std::endl;MyClass obj;// 创建一个新线程执行类的成员函数std::thread t(&MyClass::classFunction, &obj);// 主线程继续执行自己的任务for (int i = 0; i < 3; ++i) {std::cout << "Main function running, iteration: " << i << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));}// 等待新线程执行完毕t.join();std::cout << "Main function ends." << std::endl;
}// 函数将在新线程中执行
void newThreadFunction() {for (int i = 0; i < 5; ++i) {std::cout << "New thread: " << i << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));}
}int main() {mainFunction();//or// 创建一个新线程std::thread newThread(newThreadFunction);// 主线程继续执行自己的任务for (int i = 0; i < 3; ++i) {std::cout << "Main thread: " << i << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));}// 等待新线程执行完成newThread.join();return 0;
}
----更新中。。。。。
相关文章:
C++ 之多线程相关总结
C 之多线程相关总结 1.多线程相关基础知识 1.1 线程的创建和管理 1. std::thread 类: 用于创建和管理线程。通过将可调用对象(如函数、函数对象、lambda 表达式)作为参数传递给 std::thread 的构造函数,可以创建一个新的线程。…...
EF Core全局查询筛选器
目录 概述 用法 添加全局查询筛选器 禁用全局查询筛选器 概述 全局查询筛选器:EF Core 会自动将这个查询筛选器应用于涉及这个实体类型的所有 LINQ 查询。 场景:软删除、多租户。 什么是软删除? 逻辑删除,并不是真正地从数…...
【开源免费】基于SpringBoot+Vue.JS欢迪迈手机商城(JAVA毕业设计)
本文项目编号 T 141 ,文末自助获取源码 \color{red}{T141,文末自助获取源码} T141,文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...
Objective-C语言的数据库交互
Objective-C语言的数据库交互 引言 在现代应用程序开发过程中,数据库在数据存储和管理方面起着至关重要的作用。对于iOS应用开发者而言,掌握如何在Objective-C中与数据库交互显得尤为重要。本文将全面探讨Objective-C的数据库交互,包括SQLi…...
基于 Spring Boot 和 Vue.js 的全栈购物平台开发实践
在现代 Web 开发中,前后端分离的架构已经成为主流。本文将分享如何使用 Spring Boot 和 Vue.js构建一个全栈购物平台,涵盖从后端 API 开发到前端页面实现的完整流程。 1. 技术栈介绍 后端技术栈 JDK 1.8:稳定且广泛使用的 Java 版本。 Spring…...
笔记(数据运营方向)
以下是一些在工作过程中的小笔记,写的比较杂乱,后续再进行分类~ 1、掌握sql窗口函数 窗口函数又名开窗函数,属于分析函数的一种。用于解决复杂报表统计需求的功能强大的函数。窗口函数用于计算基于组的某种聚合值,它和聚合函数的…...
qt vs ios开发应用环境搭建和上架商店的记录
qt 下载链接如下 https://download.qt.io/new_archive/qt/5.14/5.14.2/qt-opensource-mac-x64-5.14.2.dmg 安装选项全勾选就行,这里特别说明下qt5.14.2/qml qt5.14.2对qml支持还算成熟,但很多特性还得qt6才行,这里用qt5.14.2主要是考虑到服…...
[cg] glDrawBuffers MRT的应用
glDrawBuffers 是 OpenGL 中的一个函数,用于指定渲染结果输出到哪些颜色缓冲区。它通常在多渲染目标(MRT, Multiple Render Targets)中使用,允许一个渲染操作同时将结果输出到多个颜色缓冲区,而不是默认情况下的单个颜…...
IO模型与NIO基础二
抽象基类之二 FilterInputStream FilterInputStream 的作用是用来“封装其它的输入流,并为它们提供额外的功能”。 它的常用的子类有BufferedInputStream和DataInputStream。 (1) BufferedInputStream的作用就是为“输入流提供缓冲功能,以及mark()和res…...
【设计模式】 单例模式(单例模式哪几种实现,如何保证线程安全,反射破坏单例模式)
单例模式 作用:单例模式的核心是保证一个类只有一个实例,并且提供一个访问实例的全局访问点。 实现方式优缺点饿汉式线程安全,调用效率高 ,但是不能延迟加载懒汉式线程安全,调用效率不高,能延迟加载双重检…...
T-SQL语言的数据库交互
T-SQL语言的数据库交互 引言 随着信息技术的不断发展,数据库在各个行业中扮演着越来越重要的角色。数据库的有效管理和优化对于企业的数据安全、效率提升和决策支持至关重要。T-SQL(Transact-SQL)作为微软SQL Server的重要扩展语言…...
【Linux系统】Ext系列磁盘文件系统二:引入文件系统(续篇)
inode 和 block 的映射 该博文中有详细解释:【Linux系统】inode 和 block 的映射原理 目录与文件名 这里有几个问题: 问题一: 我们访问文件,都是用的文件名,没用过 inode 号啊? 之前总是说可以通过一个…...
慧集通(DataLinkX)iPaaS集成平台-业务建模之域
通过左侧导航菜单〖业务建模〗→〖域〗,进入该界面;在该界面可以查看到系统中已存在的域列表。 新建域 在慧集通平台中进入【业务建模】的【域】页面,点击【新建】按钮进入新建页面;输入编码,名称、模块以及对应数据类…...
【机器学习实战】kaggle 欺诈检测---使用生成对抗网络(GAN)解决欺诈数据中正负样本极度不平衡问题
【机器学习实战】kaggle 欺诈检测---如何解决欺诈数据中正负样本极度不平衡问题https://blog.csdn.net/2302_79308082/article/details/145177242 本篇文章是基于上次文章中提到的对抗生成网络,通过对抗生成网络生成少数类样本,平衡欺诈数据中正类样本极…...
android wifi framework与wpa_supplicant的交互
android frmework直接与wpa_supplicant进行交互,使用aidl或者hidl 二、事件 framework注册事件的地方: packages/modules/Wifi/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackImpl.java class SupplicantStaIfaceCallbackImpl exte…...
初学stm32 --- flash模仿eeprom
目录 STM32内部FLASH简介 内部FLASH构成(F1) FLASH读写过程(F1) 闪存的读取 闪存的写入 内部FLASH构成(F4 / F7 / H7) FLASH读写过程(F4 / F7 / H7) 闪存的读取 闪存的写入 …...
使用C语言实现栈的插入、删除和排序操作
栈是一种后进先出(LIFO, Last In First Out)的数据结构,这意味着最后插入的元素最先被删除。在C语言中,我们可以通过数组或链表来实现栈。本文将使用数组来实现一个简单的栈,并提供插入(push)、删除(pop)以及排序(这里采用一种简单的排序方法,例如冒泡排序)的操作示…...
C语言程序环境和预处理详解
本章重点: 程序的翻译环境 程序的执行环境 详解:C语言程序的编译链接 预定义符号介绍 预处理指令 #define 宏和函数的对比 预处理操作符#和##的介绍 命令定义 预处理指令 #include 预处理指令 #undef 条件编译 程序的翻译环境和执行环…...
基于机器学习随机森林算法的个人职业预测研究
1.背景调研 随着信息技术的飞速发展,特别是大数据和云计算技术的广泛应用,各行各业都积累了大量的数据。这些数据中蕴含着丰富的信息和模式,为利用机器学习进行职业预测提供了可能。机器学习算法的不断进步,如深度学习、强化学习等…...
三种文本相似计算方法:规则、向量与大模型裁判
文本相似计算 项目背景 目前有众多工作需要评估字符串之间的相似(相关)程度: 比如,RAG 智能问答系统文本召回阶段需要计算用户文本与文本库内文本的相似分数,返回前TopK个候选文本。 在评估大模型生成的文本阶段,也需要评估…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...
c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制
目录 节点的功能承载层(GATT/Adv)局限性: 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能,如 Configuration …...
