当前位置:   article > 正文

C++ std::thread 管理线程生命周期:join 和 detach

C++ std::thread 管理线程生命周期:join 和 detach

t.join()

join 方法用于同步主线程和子线程。也就是说,当主线程调用子线程的 join 方法时,主线程会被阻塞,直到子线程完成其执行。这意味着 join 方法确保主线程等待子线程结束,然后继续执行后续代码。

  1. #include <iostream>
  2. #include <thread>
  3. void threadFunction() {
  4. std::cout << "Thread is running..." << std::endl;
  5. }
  6. int main() {
  7. std::thread t(threadFunction);
  8. // 等待线程t完成
  9. t.join();
  10. std::cout << "Thread has finished." << std::endl;
  11. return 0;
  12. }

 

在这个示例中:

  • 主线程在调用 t.join() 时会被阻塞,直到 threadFunction 线程完成。
  • 一旦子线程完成,主线程会继续执行并打印 "Thread has finished."。

t.detach()

detach 方法则是让子线程在后台独立运行,与主线程分离。分离后的线程(也称为“游离线程”)不能再被 join,它的资源会在该线程完成后自动释放。主线程会继续执行而不会等待该子线程。

  1. #include <iostream>
  2. #include <thread>
  3. #include <chrono>
  4. void threadFunction() {
  5. std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时任务
  6. std::cout << "Thread is running..." << std::endl;
  7. }
  8. int main() {
  9. std::thread t(threadFunction);
  10. // 分离线程t,使其在后台运行
  11. t.detach();
  12. std::cout << "Main thread is not blocked." << std::endl;
  13. // 主线程继续执行其他工作
  14. std::this_thread::sleep_for(std::chrono::seconds(3)); // 确保主线程不立即退出
  15. return 0;
  16. }

 

 

在这个示例中:

  • 子线程在后台独立运行,不影响主线程的执行。
  • 主线程不会等待子线程完成,而是立即继续执行。
  • 分离后的子线程在后台完成其任务并自动释放资源。

如果把std::this_thread::sleep_for(std::chrono::seconds(3)); // 确保主线程不立即退出注释掉:

 

使用场景

使用 join

  • 当你需要主线程等待子线程完成,并且需要确保子线程资源被正确释放时。
  • 用于需要顺序执行或线程间必须同步的场景。

使用 detach

  • 当你不需要等待子线程完成,并希望子线程在后台独立运行时。
  • 适用于不需要同步且子线程任务是“火忘”(fire-and-forget)类型的场景。

内存泄漏和资源泄漏风险 

  1. 未管理的资源:分离的线程继续运行,而主线程不再追踪其状态或结果。如果分离线程未能正确释放其资源,会导致资源泄漏。例如,动态分配的内存、未关闭的文件句柄等。
  2. 线程生命周期难以管理:一旦线程分离,主线程无法 join 它。这意味着主线程不能直接等待线程完成,必须通过其他方式(如条件变量或信号)来确保线程已完成。否则,主线程可能会在分离的线程完成之前退出,这样会导致未定义行为(如访问已被释放的内存)。
  3. 程序终止:如果主线程在分离的线程完成之前结束,程序中主线程所占用的资源(如堆栈、静态成员等)将会释放,但分离线程仍然在尝试访问这些资源,可能导致程序崩溃。

解决方法

  • 确保分离线程的任务尽快完成:确保分离任务不会长时间运行,以尽量减少与主线程的生命周期管理冲突。
  • 使用智能指针:使用智能指针(如 std::shared_ptr 或 std::unique_ptr)来管理动态分配的资源,确保资源在不再需要时能够自动释放。
  • 考虑线程池:如果需要频繁启动和销毁线程,使用线程池(std::thread pool)可以更高效地管理线程的生命周期,并减少资源管理的麻烦。
  • 设置主线程同步:使用某种同步机制(如条件变量、信号等),确保主线程在退出之前等待所有后台线程完成(即使是分离的线程)。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/853473
推荐阅读
相关标签
  

闽ICP备14008679号