当前位置: 首页 > 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.jsqmd.com/news/115914/

相关文章:

  • 大规模语言模型的抽象思维与创新能力培养
  • 线程(1)
  • 方达炬〖发明超新技术〗:冰堆技术;冷极冰堆建筑技术;
  • Item6--若不想使用编译器自动生成的函数,就该明确拒绝
  • 我发现LLM解析基因数据优化抗癌药剂量,患者副作用直降40%
  • 日记12.16
  • 论文AIGC查重率高怎么办?6个降AI率工具和技巧,AI率从100%降到3%! - 还在做实验的师兄
  • PCL曲面重建——为一组点云重建凸多边形/凹多边形
  • 信息与关系:涌现的三大核心原则
  • Linux文件权限
  • 28
  • 灵遁者:量子基元理论带来的新观点
  • 【补充】远程连接学校服务器操作说明
  • 本地私有知识库新选择:访答软件真实体验分享
  • 划分dp
  • 花边服饰银发红眸者山间近景
  • 日记12,15
  • Item4--确定对象被使用前已先被初始化
  • string_view
  • 当K3s遇见RustFS:轻量级边缘存储方案的探索与实践
  • 比话降AI靠谱吗?比话能降知网AI率吗? - 还在做实验的师兄
  • 树形背包
  • 八皇后问题
  • 好用做老房换新实用门窗品牌精选指南的机构
  • 基于MinIO Java SDK实现ZIP文件上传的方案与实践
  • 欧盟斥资亿欧元发布AI战略,加速产业应用与科研创新
  • 性价比高的老房换新实用门窗品牌精选指南排名
  • C++新特性
  • 快去尝试单尺作图内接正257边形吧
  • 互联网大厂Java面试:从Spring Boot到微服务架构的技术探讨