当前位置: 首页 > news >正文

【C++ 多线程实战精讲】std::thread 线程创建 / 传参 / 同步 / 智能指针 / 生命周期管理

前言

C++11 正式推出了标准多线程库<thread>,让跨平台多线程开发变得简单高效。但多线程的坑非常多:线程传参、对象生命周期、数据竞争、锁使用、指针悬空、析构崩溃……

本文基于完整可运行工程代码,带你彻底掌握:

  1. 线程创建、join /detach、生命周期管理

  2. 线程传参全场景:值、引用、指针、智能指针、移动语义

  3. 线程同步:mutex /lock_guard 解决数据竞争

  4. 自定义类 Int 配合多线程,观察构造 / 析构 / 拷贝 / 移动


一、前置:自定义 Int 类(完整四大件 + 运算符重载)

为了测试多线程下对象拷贝、移动、生命周期、传参行为,我们先实现一个带完整日志的Int类。包含:构造、析构、拷贝构造 / 赋值、移动构造 / 赋值、运算符重载。

// Int.hpp #pragma once #include <iostream> using namespace std; class Int { private: int value; public: // 构造 Int(int x, int y) :value(x + y) { cout << "Create Int(int,int): " << this << " " << value << endl; } Int(int x = 0) :value(x) { cout << "Create Int(int=0): " << this << " " << value << endl; } // 析构 ~Int() { cout << "Destroy Int: " << this << " " << value << endl; value = -1; } // 拷贝 Int(const Int& it) :value(it.value) { cout << &it << " Copy Create " << this << endl; } Int& operator=(const Int& it) { if (this != &it) value = it.value; cout << this << " operator= " << &it << endl; return *this; } // 移动 Int(Int&& it) :value(it.value) { it.value = -1; cout << &it << " Move Create " << this << endl; } Int& operator=(Int&& it) { if (this != &it) { value = it.value; it.value = -1; } cout << this << " Move operator= " << &it << endl; return *this; } // 访问 void SetValue(int x) { value = x; } int GetValue() const { return value; } int& Value() { return value; } const int& Value() const { return value; } void Print() const { cout << "value: " << value << endl; } // 类型转换 operator int() const { return value; } // 运算符 Int operator+(const Int& it) const { return Int(value + it.value); } Int operator+(int x) const { return Int(value + x); } Int& operator++() { value++; return *this; } Int operator++(int) { return Int(value++); } Int& operator--() { value--; return *this; } Int operator--(int) { return Int(value--); } // 流 ostream& operator<<(ostream& out) const { out << value; return out; } istream& operator>>(istream& in) { in >> value; return in; } }; // 全局运算符 inline ostream& operator<<(ostream& out, const Int& it) { it << out; return out; } inline istream& operator>>(istream& in, Int& it) { in >> it.Value(); return in; } inline Int operator+(int x, const Int& it) { return it + x; }

二、C++ 线程基础:创建、join、detach

2.1 线程创建(函数 / Lambda)

std::thread可以绑定:普通函数、函数对象、Lambda、成员函数。

#include <iostream> #include <thread> #include <mutex> #include <memory> #include "Int.hpp" using namespace std; void funa(int a) { cout << "thread funa: " << a << " | id: " << this_thread::get_id() << endl; } void funb(int a, int b) { cout << "thread funb: " << a << " " << b << endl; } int main() { thread t1(funa, 10); thread t2(funb, 10, 20); thread t3([](int x) { cout << "lambda: " << x << endl; }, 30); t1.join(); t2.join(); t3.join(); return 0; }

关键点:

  • join():主线程等待子线程完成,安全回收资源

  • 必须 join 或 detach,否则线程析构时程序崩溃

2.2 detach 分离线程

void funa(int a) { this_thread::sleep_for(chrono::milliseconds(10)); cout << "detach thread run: " << a << endl; } int main() { thread t(funa, 100); t.detach(); // 分离,主线程不再等待 this_thread::sleep_for(chrono::milliseconds(20)); return 0; }

注意:

  • detach 后线程独立运行,主线程退出 → 进程结束 → 子线程直接被杀死

  • 极易出现悬空对象 / 野指针 / 内存泄漏,工程慎用


三、线程传参(最容易出错!)

thread传参默认值传递(拷贝)

3.1 值传递(最安全)

void funa(Int it) { it.Print(); } int main() { Int a(10); thread t(funa, a); // 会拷贝 t.join(); return 0; }

3.2 引用传递(必须用 std::ref)

void funa(Int& it) { it.SetValue(100); it.Print(); } int main() { Int a(10); thread t(funa, ref(a)); // 不加 ref 编译失败 t.join(); cout << "main: " << a.GetValue() << endl; return 0; }

3.3 裸指针传递(危险!)

void funa(Int* p) { if (p) p->Print(); } int main() { thread t; { Int a(10); t = thread(funa, &a); } // a 已经销毁! t.join(); // 悬空指针,未定义行为 return 0; }

3.4 智能指针传递(最推荐)

shared_ptr 值传递(自动管理生命周期)shared_ptr 引用传递(不增加计数,高效)

void funa(shared_ptr<Int> sp) { if(sp) sp->Print(); } int main() { thread t; { auto sp = make_shared<Int>(10); t = thread(funa, sp); // 拷贝,计数+1 } t.join(); // 安全 return 0; }

shared_ptr 引用传递(不增加计数,高效)

void funa(const shared_ptr<Int>& sp) { if (sp) { sp->Print(); } } int main() { auto sp = make_shared<Int>(10); thread t(funa, ref(sp)); t.join(); return 0; }

3.5 移动语义传递(无拷贝)

void funa(Int&& it) { it.Print(); } int main() { Int a(10); thread t(funa, move(a)); t.join(); return 0; }

四、线程同步:mutex + lock_guard(解决数据竞争)

多线程同时读写共享变量 =数据竞争= 结果错乱。

必须用互斥锁保护临界区。

const int n = 10; const int m = 10; mutex mtx; void funa(char ch) { for (int i = 0; i < n; ++i) { lock_guard<mutex> lock(mtx); // 自动加锁解锁 for (int j = 0; j < m; ++j) { printf("%c ", ch); } printf("\n"); } printf("------------------------\n"); } int main() { thread th[5]; for (int i = 0; i < 5; ++i) { th[i] = thread(funa, 'A' + i); } for (auto& t : th) t.join(); return 0; }

关键点:

  • lock_guard:RAII 风格,异常安全

  • 临界区越小越好

  • 不要重复加锁、不要死锁


五、多线程高频坑点总结(必背)

  1. thread 对象必须 join 或 detach

  2. 默认传参是拷贝,传引用必须std::ref

  3. 不要向线程传递局部对象指针 / 引用(会悬空)

  4. 优先使用 shared_ptr 管理线程对象生命周期

  5. 共享资源必须加锁,否则数据竞争

  6. detach 极其危险,主线程退出会直接杀死子线程

  7. 不要在锁内做耗时操作,降低并发效率

  8. 移动语义可以避免拷贝,提升效率


六、整篇博客核心总结(高质量升华)

C++ 多线程编程的核心,其实就三件事:

  1. 线程生命周期管理:join /detach/ 智能指针托管

  2. 参数传递安全:值 / 移动语义 / 智能指针

  3. 共享资源同步:mutex /lock_guard/ 原子变量

http://www.jsqmd.com/news/537290/

相关文章:

  • 点击a标签包裹的绝对定位的元素不触发a链接跳转的处理
  • 基于Python的宠物爱心组织管理系统毕设源码
  • 3D高斯泼溅(3DGS)实战:从零开始提取Mesh的完整流程与避坑指南
  • 像素幻梦·创意工坊实战教程:LoRA插件加载与像素风格微调完整步骤
  • 从Autoencoder到VAE:探索生成模型的演进之路
  • 深入解析UniApp中的package.json:从基础配置到高级技巧
  • 若依框架接口测试实战:从登录到用户列表查询的完整流程(Apifox版)
  • 零代码玩转视觉定位:基于Qwen2.5-VL的Chord模型,Gradio界面快速上手
  • Kevin的矩阵【牛客tracker 每日一题】
  • OpenClaw异常处理:Qwen3-32B-Chat任务中断恢复机制
  • nomic-embed-text-v2-moe从零开始:开源权重+训练数据+完整推理链路说明
  • CogVideoX-2b显存优化实测:12GB显存流畅运行,性价比之选
  • LangGraph Platform本地部署实战:用Docker和CLI快速搭建你的第一个AI Agent微服务
  • 2026最新 Springboot+vue在线考试系统设计与实现
  • 2026泸州艺考生文化课冲刺可靠机构推荐指南:华升教育学校、华升教育学校、泸州华升教育培训机构合规吗、泸州华升教育培训机构合规吗选择指南 - 优质品牌商家
  • ALC5651 Codec实战:如何消除Android音频播放中的POP声(附完整寄存器配置)
  • 用Wireshark抓包分析CAN错误帧:手把手教你定位CRC/波特率/采样点问题
  • MindSpore Ops 模块核心概览学习
  • 2026年比较好的钛极岩铸不粘锅/物理不粘锅人气公司推荐 - 品牌宣传支持者
  • 如何在普通PC上低成本部署Qwen3?VLLM轻量化配置指南
  • 2026最新 Springboot+Vue在线学习系统设计与实现
  • Qwen3-ForcedAligner-0.6B开发者案例:基于Streamlit的双模型协同架构解析
  • 2026年靠谱的气力输送设备/气力输送系统/颗粒气力输送/粉体气力输送源头厂家推荐 - 品牌宣传支持者
  • SDMatte在跨境电商中的提效实践:多语言商品图批量生成透明底素材
  • 参数优化技巧:如何调整提示词,让生成的真人皮肤更自然、细节更丰富?
  • Z-Image-GGUF效果展示:抽象艺术、人物写真、风景摄影三类高质量作品集
  • RWKV7-1.5B-g1a轻量生成能力:120字内产品文案生成效果惊艳展示
  • 2026宜宾靠谱中高端家装公司推荐榜:附近装饰公司推荐、靠谱的装修公司有哪些、宜宾中高端装饰公司、宜宾别墅装饰公司选择指南 - 优质品牌商家
  • 别再只盯着W25Q128了!手把手教你搞定STM32驱动W25Q256(含4字节地址模式切换)
  • 雪女-斗罗大陆-造相Z-Turbo镜像部署全攻略:开箱即用的文生图工具