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

线程(2)

std::thread 的基础用法:

  • 构造函数:
    • std::thread(Function, Args...): 接受一个函数和其参数来创建并启动线程。
    • 拷贝构造被禁用 (Deleted): std::thread t2 = t1; 是非法的,线程对象不能被拷贝。
    • 支持移动构造 (Move Constructor): std::thread t2 = std::move(t1); 是合法的,所有权转移。
  • 参数传递陷阱:
    • 默认按值拷贝: 即使函数参数声明为引用,std::thread 构造函数也会默认拷贝参数。
    • 传引用需用 std::ref 如果想真正传递引用(在线程内修改外部变量),必须使用 std::ref(var) 包装参数。
  • 成员函数调用:
    • 语法:std::thread(&ClassName::MethodName, &object, args...)
    • 必须传入对象指针(或地址)作为第二个参数,以确定在这个对象上调用该方法。
  • 线程管理:
    • join(): 阻塞等待线程结束。
    • detach(): 分离线程,使其在后台运行(需注意生命周期问题)。
    • get_id(): 获取线程 ID。

1. detach() 的“坑”:主线程退出,全员陪葬

现象:运行代码,发现子线程 func5 里的打印语句并没有输出,程序就结束了。 核心原理:

  • 非独立进程: detach() 不会把线程变成一个独立的进程。它只是把线程对象 (std::thread t) 和后台运行的线程执行流“断开联系”。
  • 共存亡: 子线程依然属于当前进程。如果主线程(Main Thread)结束,整个进程(Process)就会销毁,操作系统会强行杀死该进程下所有的线程,无论它们是否被 detach。
  • 资源泄漏风险: 讲师提到如果 detach 的线程还在访问某些资源(如文件、内存),主线程退出导致的强制终止可能导致资源未正确释放。

代码演示:

void func5() {std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时std::cout << "Thread 5 working..." << std::endl;      // 这句可能来不及打印
}int main() {std::thread t5(func5);t5.detach(); // 分离线程,让它在后台跑// 主线程立刻结束return 0; // 结果:进程销毁,后台的 t5 还没醒过来就被系统杀死了。
}

2. detach 后严禁 join

现象: 尝试先 detach(),然后紧接着调用 join(),结果程序抛出“系统错误”(System Error)并崩溃。 核心原理:

  • std::thread 对象只是一个句柄(Handle)
  • 当你调用 detach() 后,这个句柄就和物理线程断绝关系了。
  • 此时 t5 变成了一个空的壳子(Empty Shell)。你不能对一个空壳子调用 join(),这属于非法操作。

代码演示:

std::thread t5(func5);
t5.detach(); // t5 不再持有线程if (t5.joinable()) {t5.join(); 
} else {// detach 后,joinable() 变为 false// 再次 join 会 crash// t5.join(); // ❌ 崩溃:Invalid Argument
}

3. joinable() 的判断作用

现象: 调用 t5.joinable(),打印结果为 0 (false)。 最佳实践: 在调用 join()detach() 之前,永远建议先检查 joinable()

  • 一个默认构造的线程 std::thread t; 是不可 join 的。
  • 一个已经 join() 过的线程是不可 join 的。
  • 一个已经 detach() 过的线程是不可 join 的。

4. 线程所有权的转移 (std::move)

现象: 演示了 t6_2 = std::move(t6_1),然后尝试操作 t6_1,导致异常。 核心原理:

  • std::thread独占资源(类似 unique_ptr)。一个物理线程只能被一个对象管理。
  • std::move 发生了所有权转移
    • t6_2 拿到了线程的控制权。
    • t6_1 变成了空壳(Null)。
  • 后果: 转移后,原对象 t6_1 就不能再进行任何线程操作(如 join/detach/get_id),否则会报错或行为未定义。

代码演示:

void func() {}int main() {std::thread t1(func);// t2 接管 t1 的线程,t1 变空std::thread t2 = std::move(t1); // t1.join(); // ❌ 错误:t1 已经空了t2.join(); // ✅ 正确:t2 现在负责管理线程
}
http://www.gsyq.cn/news/127865.html

相关文章:

  • Item9--绝不在构造和析构过程中调用虚函数
  • Item5--了解 C++ 默默编写并调用了哪些函数
  • 日记1217
  • 本地私有知识库新选择:访答软件真实体验分享
  • 日记12,15
  • string_view
  • 比话降AI靠谱吗?比话能降知网AI率吗? - 还在做实验的师兄
  • 好用做老房换新实用门窗品牌精选指南的机构
  • 快去尝试单尺作图内接正257边形吧
  • nginx安装步骤详解 - 教程
  • C020基于博途西门子1200PLC鸡饲料生产线控制系统仿真
  • 第9章 顺序容器
  • 基于SpringBoot+Vue的乡镇农村建设用地管理系统的设计与实现
  • Git 与 SVN 区别 - 详解
  • 第6章 函数
  • C++新特性
  • 亲测十大灵活用工平台复盘
  • 目录---behaviac
  • 20251220
  • 线索二叉树
  • 第3章 字符串向量数组
  • 曲线的极坐标方程输入法 | Desmos 玩法系列 02
  • AVL
  • 鸿蒙系统
  • STM32学习——编码器接口测速
  • BST
  • 卡帕西年度预测:大模型只释放10%潜力,2025年AI发展6大趋势
  • 学Simulink——基础MPPT控制场景实例:基于Simulink的电导增量法(INC)光伏MPPT仿真
  • 模板模式
  • 模板和策略模式的区别