0

0

C++怎么进行多线程编程_C++中thread类的用法【详解】

尼克

尼克

发布时间:2026-03-16 21:27:23

|

195人浏览过

|

来源于php中文网

原创

std::thread 构造后必须 detach 或 join,否则析构时调用 std::terminate() 导致程序崩溃;正确做法仅两种:join() 等待完成,或 detach() 后台运行,且需注意传参语义、生命周期及 thread_local 初始化时机。

c++怎么进行多线程编程_c++中thread类的用法【详解】

std::thread 构造后必须 detach 或 join

不处理的 std::thread 对象在析构时会调用 std::terminate(),程序直接崩溃——这不是警告,是硬性约束。常见错误是局部创建线程后忘了管它,比如写成:

void bad_example() {
    std::thread t([]{ /* do work */ });
    // t 离开作用域,自动析构 → terminate()
}

正确做法只有两种:join()(等待完成)或 detach()(后台运行,不再关联)。选哪个取决于场景:

  • join():适合需要结果、或必须等子任务结束再继续的逻辑(如初始化阶段)
  • detach():适合“发出去就不管”的异步日志、心跳上报等,但要注意:被 detach 的线程不能访问栈上变量,否则极易野指针
  • 如果线程可能提前退出,又不确定是否已 join 过,用 t.joinable() 判断再操作,避免重复 join 报错

传参到 std::thread 会默认 move 或 copy,不是引用

std::thread(f, x) 时,x 会被拷贝进线程私有栈;写 std::thread(f, std::ref(x)) 才真正传引用。很多人误以为加了 & 就行,但这样写是错的:

int val = 42;
std::thread t([](int& v) { v = 100; }, &val); // ❌ 编译失败:&val 是右值指针,不能绑定到 int&

必须显式用 std::ref 包装:

立即学习C++免费学习笔记(深入)”;

std::thread t([](int& v) { v = 100; }, std::ref(val)); // ✅

容易踩的坑:

会译·对照式翻译
会译·对照式翻译

会译是一款AI智能翻译浏览器插件,支持多语种对照式翻译

下载
  • lambda 捕获 [&] 不等于线程参数传引用——捕获的是创建 lambda 时的上下文,而线程启动是之后的事,栈变量可能已销毁
  • 移动语义生效时(比如传 std::unique_ptr),原变量立刻失效,别在线程外再访问
  • 传 raw pointer 要格外小心生命周期,推荐优先用 std::shared_ptr 管理共享资源

thread_local 变量不是“每个线程一份”那么简单

thread_local 确实为每个线程提供独立副本,但它只在**首次访问时构造**,且**在线程结束时自动析构**。这带来两个隐含行为:

  • 如果某线程从没访问过该变量,就不会构造,也不会析构——不能靠它做“线程启动即初始化”的副作用
  • 静态存储期的 thread_local(如全局或 namespace 作用域)支持动态初始化,但不同编译器对初始化顺序的保证程度不一,跨 DLL 或 shared object 时尤其危险
  • static 一起用要警惕:比如 static thread_local std::vector<int> cache;</int>,每个线程第一次调用函数时才构造,且无法手动控制构造时机

更稳妥的做法是配合 std::call_once + std::once_flag 做延迟初始化,而不是依赖 thread_local 的隐式构造。

不要用裸 thread 管理复杂生命周期

直接用 std::thread 适合简单、短生命周期任务。一旦涉及线程池、任务队列、取消机制、异常传播,裸 thread 很快失控。典型问题包括:

  • 线程意外退出时,没有统一错误处理路径,异常直接终止进程
  • 无法优雅停止:没有标准方式通知线程“请尽快退出”,只能轮询 flag 或用条件变量,但 flag 本身需同步
  • 资源泄漏风险高:比如线程里 new 了内存,但没 catch 异常,析构函数不会执行

这时候应该换方案:

  • std::jthread(C++20):自带自动 join 和可协作中断(request_stop()
  • 封装自己的 task runner,用 std::promise/std::future 传递结果和异常
  • 第三方库如 folly::Executorboost::asio::thread_pool 更适合生产级调度

多线程最难的从来不是“怎么启一个线程”,而是“怎么让它安全地开始、通信、出错、结束”。std::thread 只解决第一个字。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

215

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

193

2025.11.08

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

62

2026.01.05

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

448

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

606

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

786

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

379

2025.12.24

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

33

2026.01.21

chatgpt使用指南
chatgpt使用指南

本专题整合了chatgpt使用教程、新手使用说明等等相关内容,阅读专题下面的文章了解更多详细内容。

0

2026.03.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 11.5万人学习

C 教程
C 教程

共75课时 | 5.5万人学习

C++教程
C++教程

共115课时 | 22.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号