【C++ 多线程实战精讲】std::thread 线程创建 / 传参 / 同步 / 智能指针 / 生命周期管理
前言C11 正式推出了标准多线程库thread让跨平台多线程开发变得简单高效。但多线程的坑非常多线程传参、对象生命周期、数据竞争、锁使用、指针悬空、析构崩溃……本文基于完整可运行工程代码带你彻底掌握线程创建、join /detach、生命周期管理线程传参全场景值、引用、指针、智能指针、移动语义线程同步mutex /lock_guard 解决数据竞争自定义类 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(int0): 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、detach2.1 线程创建函数 / Lambdastd::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::refvoid 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_ptrInt sp) { if(sp) sp-Print(); } int main() { thread t; { auto sp make_sharedInt(10); t thread(funa, sp); // 拷贝计数1 } t.join(); // 安全 return 0; }shared_ptr 引用传递不增加计数高效void funa(const shared_ptrInt sp) { if (sp) { sp-Print(); } } int main() { auto sp make_sharedInt(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_guardmutex 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_guardRAII 风格异常安全临界区越小越好不要重复加锁、不要死锁五、多线程高频坑点总结必背thread 对象必须 join 或 detach默认传参是拷贝传引用必须std::ref不要向线程传递局部对象指针 / 引用会悬空优先使用 shared_ptr 管理线程对象生命周期共享资源必须加锁否则数据竞争detach 极其危险主线程退出会直接杀死子线程不要在锁内做耗时操作降低并发效率移动语义可以避免拷贝提升效率六、整篇博客核心总结高质量升华C 多线程编程的核心其实就三件事线程生命周期管理join /detach/ 智能指针托管参数传递安全值 / 移动语义 / 智能指针共享资源同步mutex /lock_guard/ 原子变量
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2450069.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!