C++ 多线程简要讲解

        std::thread是 C++11 标准库中用于多线程编程的核心类,提供线程的创建、管理和同步功能。下面我们一一讲解。

一.构造函数

官网的构造函数如下:

1.默认构造函数和线程创建

thread() noexcept;

作用:创建一个 std::thread 对象,但不关联任何实际线程​(即空线程对象)。

如:

std::thread t;  // 空线程对象,不执行任何操作

注意:空线程对象不可调用 join() 或 detach(),需先绑定有效线程。

2.初始化构造函数

template <class Fn, class... Args>
explicit thread(Fn&& fn, Args&&... args);
  • 作用创建一个新线程,新线程会立即执行 fn(args...)函数
  • 参数
    • fn:可调用对象(函数、Lambda、函数对象等)。
    • args:传递给 fn 的参数

如: 

void print(int x) { std::cout << x; }
std::thread t(print, 42);  // 线程执行 print(42)
t.join();

这里要注意下面几点

  • explicit 禁止隐式类型转换(如避免误将函数指针转线程对象)。
  • 参数默认按值拷贝传递,若需传引用需用 std::ref
  • 示例:
int x = 42;
std::thread t([](int& v) { v++; }, std::ref(x));  // 传递引用

3.拷贝构造函数(被删除)​

thread(const thread&) = delete; 

  • 作用:禁止拷贝构造线程对象(线程资源不可复制)。
  • 示例:
  • std::thread t1([]{ /* ... */ });
    std::thread t2 = t1;  // 编译错误!拷贝构造被禁用
  • 原因:线程是独占资源,拷贝可能导致线程重复管理(如多次 join())。

 4.移动构造函数

thread(thread&& x) noexcept;
  • 作用:将线程所有权从 x 转移到新对象(x 变为空线程对象)。
  • 示例
    std::thread t1([]{ /* ... */ });
    std::thread t2 = std::move(t1);  // t1 变为空,t2 接管线程
    t2.join();

这里要注意下面几点:

  • 移动后,原线程对象 x 不再关联任何线程。
  • 用于将线程对象存入容器或转移所有权:std::vector<std::thread> threads; threads.push_back(std::thread([]{ /* ... */ })); // 必须用移动语义
std::vector<std::thread> threads;
threads.push_back(std::thread([]{ /* ... */ }));  // 必须用移动语义

 二.赋值运算符重载

1. 移动赋值运算符(Move Assignment)

thread& operator=(thread&& rhs) noexcept;

  • 关键行为
    • 当前对象会先释放自己原本持有的线程资源(如果存在)。
    • 接管 rhs 的线程所有权,rhs 变为空线程对象​(不再关联任何线程)。
    • 操作是原子的,且标记为 noexcept(保证不抛出异常)。
  • 示例
    std::thread t1([]{ /* 任务 1 */ });
    std::thread t2;
    t2 = std::move(t1);  // t1 的线程所有权转移给 t2,t1 变为空
    t2.join();
  • 典型用途
    • 将线程对象存入容器(如 std::vector<std::thread>)。
    • 动态管理线程所有权(如线程池)。

2. 拷贝赋值运算符(被删除)​

thread& operator=(const thread&) = delete;

  • 作用:​禁止拷贝赋值​(编译时报错)。
  • 原因
    • 线程是独占资源,拷贝会导致多个对象管理同一线程,引发重复 join() 或 detach()
    • 保证线程对象的唯一所有权,避免资源管理冲突。
  • 错误示例
    std::thread t1([]{ /* ... */ });
    std::thread t2;
    t2 = t1;  // 编译错误!拷贝赋值被禁用

  三.线程等待和线程分离

        线程等待就是让主线程等待子线程执行完毕,首先我们要明白为什么要进行线程等待

1.主线程是进程的入口,若主线程执行完毕,操作系统会直接终止整个进程(包括所有子线程),无论子线程是否完成任务。

2.子线程可能持有共享资源(如内存、文件句柄、网络连接),若主线程不等待子线程结束就退出,可能导致:资源泄漏​(如未关闭的数据库连接)和数据竞争​(子线程访问已被主线程释放的内存,导致崩溃)。

3.部分情况下线程执行计算或数据处理后,主线程需要汇总结果

        线程分离就是用于解除线程与其创建者(如主线程)的关联,使得子线程在终止后能够自动释放资源,无需其他线程显式调用 join() 等待或回收。

        下面我们就来讲解一下线程等待和线程分离函数join() 和 detach()

join():在主线程中调用阻塞主线程,直到当前线程执行完毕,就是让主线程等待子线程执行完毕

detach():分离线程,使其在后台独立运行(无法再管理)。

必须在 std::thread 对象销毁前调用 join() 或 detach(),否则程序终止。

std::thread t([]{ /* ... */ });if (t.joinable()) {t.join();   // 或 t.detach();
}

四.线程 ID 和命名

  • get_id():获取线程唯一标识符。
  • std::this_thread 命名空间提供当前线程操作。有get_id(),yield(),sleep_for()等操作。
std::thread t([]{ std::cout << "Thread ID: " << std::this_thread::get_id() << "\n";
});
std::cout << "Main thread ID: " << t.get_id() << "\n";
t.join();

五.线程中的同步机制

1. 互斥量 std::mutex

防止多个线程同时访问共享资源。

std::mutex mtx;
int counter = 0;void safe_increment() {std::lock_guard<std::mutex> lock(mtx); // 自动加锁解锁counter++;
}std::thread t1(safe_increment);
std::thread t2(safe_increment);
t1.join(); t2.join();

2. 条件变量 std::condition_variable

用于线程间的条件同步。

std::mutex mtx;
std::condition_variable cv;
bool ready = false;void wait_thread() {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, []{ return ready; }); // 等待条件满足std::cout << "Ready!\n";
}void signal_thread() {std::this_thread::sleep_for(std::chrono::seconds(1));{std::lock_guard<std::mutex> lock(mtx);ready = true;}cv.notify_one(); // 通知等待线程
}std::thread t1(wait_thread);
std::thread t2(signal_thread);
t1.join(); t2.join();

六.实践操作:

用两个线程分别交替打印 1-100 的奇数和偶数,通过互斥锁和条件变量实现交替输出:

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>using namespace std;int num = 1;                        // 共享计数器
mutex mtx;                          // 互斥锁
condition_variable cv;              // 条件变量
const int MAX_NUM = 100;            // 最大值void print_odd() {while (true) {unique_lock<mutex> lock(mtx);// 等待条件:数字为奇数或超过最大值cv.wait(lock, [] { return (num % 2 == 1) || (num > MAX_NUM); });if (num > MAX_NUM) break;cout << "Odd:  " << num << endl;num++;                      // 递增到偶数lock.unlock();cv.notify_all();            // 唤醒另一个线程}
}void print_even() {while (true) {unique_lock<mutex> lock(mtx);// 等待条件:数字为偶数或超过最大值cv.wait(lock, [] { return (num % 2 == 0) || (num > MAX_NUM); });if (num > MAX_NUM) break;cout << "Even: " << num << endl;num++;                      // 递增到奇数lock.unlock();cv.notify_all();            // 唤醒另一个线程}
}int main() {thread t1(print_odd);thread t2(print_even);t1.join();t2.join();return 0;
}

运行结果

        c++的线程就讲到这里,有帮助的话就点点赞吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/73493.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vscode HTML5新增元素及属性

一、‌HTML5 语义化标签 HTML5 语义化标签&#xff08;Semantic Elements&#xff09;是一组 ‌具有明确含义的 HTML 元素‌&#xff0c;通过标签名称直接描述其内容或结构的功能&#xff0c;而非仅作为样式容器&#xff08;如 <div> 或 <span>&#xff09;。它们旨…

【PostgreSQL教程】PostgreSQL 特别篇之 语言接口Python

博主介绍:✌全网粉丝22W+,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物联网、机器学习等设计与开发。 感兴趣的可…

Three学习入门(四)

9-Three.js 贴图与材质学习指南 环境准备 <!DOCTYPE html> <html> <head><title>Three.js Texture Demo</title><style> body { margin: 0; } </style> </head> <body><script src"https://cdnjs.cloudflare.…

前端NVM安装

https://v0.dev/chat/settings 本地启动环境 1安装 nvm 2安装node nvm install v18.19.0 nvm install v20.9.0 nvm use 18 node -v 3安装 pnpm npm install -g pnpm 或者 npm i -g pnpm 4启动 代码 目录下 执行 pnpm i pnpm run dev 4.1到代码目录下 4.2直接cmd…

蓝桥杯算法精讲:二分查找实战与变种解析

适合人群&#xff1a;蓝桥杯备考生 | 算法竞赛入门者 | 二分查找进阶学习者 目录 一、二分查找核心要点 1. 算法思想 2. 适用条件 3. 算法模板 二、蓝桥杯真题实战 例题&#xff1a;分巧克力&#xff08;蓝桥杯2017省赛&#xff09; 三、二分查找变种与技巧 1. 查找左边…

cmd命令查看电脑的CPU、内存、存储量

目录 获取计算机硬件的相关信息的命令分别的功能结果展示结果说明获取计算机硬件的相关信息的命令 wmic cpu get name wmic memorychip get capacity wmic diskdrive get model,size,mediaType分别的功能 获取计算机中央处理器(CPU)的名称 获取计算机内存(RAM)芯片的容量…

SCI论文阅读指令(特征工程)

下面是一个SCI论文阅读特征工程V3.0&#xff0c;把指令输入大模型中&#xff0c;并上传PDF论文&#xff0c;就可以帮你快速阅读论文。 优先推荐kimi&#xff0c;当然DeepSeek、QwQ-32B等大语言模型也可以。测试了一下总结的还不错&#xff0c;很详细。 请仔细并深入地阅读所提…

如何监控 SQL Server

监控 SQL Server 对于维护数据库性能、确保数据可用性和最大限度地减少停机时间至关重要。随着企业越来越依赖数据驱动的决策&#xff0c;高效的SQL Server监控策略能显著提升组织生产力和用户满意度。 为什么要监控 SQL Server SQL Server 是许多关键应用程序的支柱&#xf…

python脚本处理excel文件

1.对比perl和python 分别尝试用perl和python处理excel文件&#xff0c;发现perl的比较复杂&#xff0c;比如说read excel就有很多方式 Spreadsheet::Read use Spreadsheet::ParseExcel 不同的method&#xff0c;对应的取sheet的cell方式也不一样。更复杂的是处理含有中文内…

3、pytest实现参数化

在 pytest 中&#xff0c;参数化&#xff08;parametrization&#xff09;是一种强大的功能&#xff0c;可以让你用不同的输入数据重复执行同一个测试函数。这种功能非常有用&#xff0c;可以帮助你显著减少重复代码并提高测试覆盖率。 参数化的主要作用是&#xff1a; 测试多…

Cursor:超强AI变成神器

是一个强大的 AI 编程助手&#xff0c;可以帮助开发者快速地编写、编辑和讨论代码&#xff0c;支持 Python、Java、C# 等多种编程语言&#xff0c;并且可以与 GitHub、Slack 等平台集成。 Cursor 是什么&#xff1f; 想象一下&#xff0c;你有一个能把你的创意变成现实的造梦 …

画秒杀系统流程图

秒杀系统流程图 秒杀系统关键点 高并发处理: 使用网关&#xff08;如 Nginx&#xff09;进行流量限流&#xff0c;避免过载。分布式锁或 Redis 原子操作控制并发。 活动状态检查: Redis 存储活动状态&#xff08;如 seckill:activity:1:status&#xff09;&#xff0c;快速…

【js逆向入门】图灵爬虫练习平台 第九题

地址&#xff1a;aHR0cHM6Ly9zdHUudHVsaW5ncHl0b24uY24vcHJvYmxlbS1kZXRhaWwvOS8 f12进入了debugger&#xff0c;右击选择一律不在此处暂停&#xff0c; 点击继续执行 查看请求信息 查看载荷&#xff0c;2个加密参数&#xff0c;m和tt 查看启动器&#xff0c;打上断点 进来 往…

Vue中的状态管理器Vuex被Pinia所替代-上手使用指南

Pinia.js 是新一代的状态管理器&#xff0c;由 Vue.js团队中成员所开发的&#xff0c;因此也被认为是下一代的 Vuex&#xff0c;即 Vuex5.x&#xff0c;在 Vue3.0 的项目中使用也是备受推崇 Pinia.js 有如下特点&#xff1a; 完整的 typescript 的支持&#xff1b;足够轻量&…

向量数据库学习笔记(1) —— 基础概念

一、 嵌入模型 Embedding Models 嵌入模型是将复杂数据&#xff08;如文本、图像、音频等&#xff09;转换为向量表示的机器学习模型 1. 核心概念 嵌入(Embedding)&#xff1a;将高维、非结构化的数据映射到低维、稠密的向量空间 向量表示&#xff1a;输出固定长度的数值向量…

[NO-WX179]基于springboot+微信小程序的在线选课系统

[NO-WX179]基于springboot微信小程序的在线选课系统 1、管理员角色&#xff08;web端&#xff09;&#xff1a;2、教师角色&#xff08;web端&#xff09;&#xff1a;3、用户角色&#xff08;小程序或web端&#xff09;&#xff1a;4、部分运行截图管理端--教师管理管理端--学…

2025年渗透测试面试题总结-某 长亭(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 长亭 一、Spring SpEL表达式注入漏洞 1. 技术原理 2. 利用条件 3. 攻击方法 4. 防御策略 二、Jav…

conda环境下解决gitk乱码模糊

关键词 conda、git、gitk、git gui、模糊、linux、乱码 现象 操作系统&#xff1a;ubuntu24.04 conda版本&#xff1a;25.1.1 正常的终端里gitk显示不会模糊 但是在conda创建的python虚拟环境中使用gitk&#xff0c;字体开始变得模糊不清 分析 根据deepseek的原因原因分析…

【C++项目实战】:基于正倒排索引的Boost搜索引擎(1)

1. 项目的相关背景与目标 针对boost网站没有搜索导航功能&#xff0c;为boost网站文档的查找提供搜索功能 站内搜索&#xff1a;搜索的数据更垂直&#xff0c;数据量小 类似于cplusplus.com的搜索 2.搜索引擎的相关宏观原理 3.技术栈和项目环境 技术栈&#xff1a;C/C&am…

汽车高级驾驶辅助系统应用存储MRAM

高级驾驶辅助系统和先进的互连航空电子技术等应用要求元件能够承受恶劣的环境条件&#xff0c;并具有较高的耐用性。闪存虽然在某些条件下性能可靠&#xff0c;但在耐用性方面存在局限性&#xff0c;因此无法满足这些严格的要求。 在实时传感器数据处理或高可靠性通信等对时间…