std::thread 基础用法
1.std::thread 简介 std::thread 是C++11标准库中提供的线程类,用于创建和管理线程。它是现代C++多线程编程的基础,参考:cppreference.cn/w/cpp/threa…
2.基本线程创建
- std::thread 的构造函数,用来传入需要子线程执行的操作。
- joinable() 返回一个布尔值,表示线程对象是否关联着一个可被 join/detach 的活动线程。
- join() 阻塞当前线程,直到被 join 的线程执行完毕。
运行结果如下:
3.重点:std::thread类对象构造完毕之后,就已经处于就绪状态了,一旦系统调度器给它分配资源,它就会立即开始运行。理论上你可以认为,构造和开始运行是同时开始的。
线程创建与生命周期管理
std::stread其实就是构造的时候传入一个被执行的方法,然后就会在子线程中执行这个方法直到这个方法结束,这个方法不仅仅是函数,可以有很多形式:
-
静态函数
-
成员函数
-
lambda表达式
-
函数对象
-
使用std::bind
join() 与 detach() 的区别
-
join():主线程等待子线程完成,保持关联,同步执行
-
detach():主线程不等待子线程,完全分离,异步执行
[豆包:] 🎯 主人,我用大白话给你讲明白 std::bind !
一句话总结: std::bind 就是给函数「打包」,把函数和它要用的参数、对象绑在一起,变成一个可以直接调用的「成品函数」。
一、先搞懂:你代码里为啥要用它?
你要在线程里跑一个类的成员函数,比如 ThreadManager 里的 member_function 。 成员函数有个「小脾气」:它必须知道自己是属于哪个对象的(也就是 this 指针),不然没法干活。
但 std::thread 线程只认「直接能调用的函数」,不认带 this 的成员函数。 这时候 std::bind 就来当「中间人」了:
我帮你把「成员函数 + 对应的对象 + 要传的参数」打包成一个完整的、能直接调用的函数,线程直接用这个打包好的就行!
二、举个生活例子,一秒懂
你要让外卖员(线程)给你送奶茶:
- 「点奶茶」这个动作 = 类的成员函数(必须知道给谁点,也就是对象)
- 「你」 = 类的对象实例( &manager )
- 「三分糖、少冰」 = 函数参数( 5 )
外卖员(线程)只知道「送奶茶」,不知道给谁送、要什么口味。 std::bind 就相当于:
把「给XX点三分糖少冰的奶茶」这个完整指令打包好,给外卖员。 外卖员拿到这个指令,直接执行就行,不用再问「给谁点?要啥口味?」
三、对应到你代码里,就是这回事
cpp
// 1. 打包:把「成员函数 + 对象 + 参数」绑成一个新函数 auto bound_func = std::bind(&ThreadManager::member_function, &manager, 5); // 2. 线程直接用这个打包好的函数 std::thread t5(bound_func);
- 打包前: member_function 是个半成品,必须给它对象和参数才能用
- 打包后: bound_func 是个成品,直接调用 bound_func() 就等于 manager.member_function(5)
- 线程拿到 bound_func ,直接跑就行,啥都不用管
四、 std::bind 还能干嘛?(超简单版)
除了打包成员函数,它还有两个常用小功能:
1. 提前填好部分参数
比如一个函数要两个数相加,你可以用 bind 把第一个数固定成10,之后只需要传第二个数就行。
2. 换参数顺序
比如函数是 print(a, b) ,你可以用 bind 让它变成 print(b, a) ,调用的时候自动换顺序。
五、现在更简单的替代方案(不用记bind语法)
现在C++里,用lambda表达式比 std::bind 更直白,一眼就能看懂:
cpp
// 直接用lambda把成员函数包起来,效果和bind完全一样
std::thread t5( {
manager.member_function(5);
});
意思就是:线程执行这个lambda,lambda里直接调用对象的成员函数,不用绕弯子。
六、一句话收尾
std::bind 就是个函数打包工具,专门解决「成员函数没法直接给线程用」的问题,把半成品函数变成成品,让线程能直接跑。