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

C++编程指南21 - 线程detach后其注意变量的生命周期

一:概述

        如果一个线程被 detach() 了,那么它的生命周期将独立于创建它的作用域。因此,该线程只能安全地访问:

  1. 全局变量(global/static objects)
  2. 堆上分配的对象(free-store allocated objects,即 new / make_unique() 创建的对象) 其他作用域的对象可能会在线程访问它们之前被销毁,导致 悬空指针(dangling pointer) 和 未定义行为。

二:示例代码

        下面以一段代码来介绍下前面说的这种情况:

#include <iostream>
#include <thread>
#include <memory>

void f(int* p) {
    *p = 99;  // 可能访问悬空指针
}

int glob = 33;  // 全局变量

void some_fct(int* p) {
    int x = 77;
    std::thread t0(f, &x);         // 错误!x 是局部变量
    std::thread t1(f, p);          // 错误!p 可能指向局部变量
    std::thread t2(f, &glob);      // OK!glob 是全局变量
    auto q = std::make_unique<int>(99);
    std::thread t3(f, q.get());    // 错误!q 在 some_fct 结束时销毁

    t0.detach();
    t1.detach();
    t2.detach();
    t3.detach();
}

    在这段代码中,线程detach后,会有以下几种情况发生:

  1. t0(f, &x);t1(f, p);

    • xsome_fct() 的局部变量,p 可能指向局部变量。
    • t0t1 可能会在 some_fct() 结束后访问已销毁的变量,导致 未定义行为。
  2. t3(f, q.get());

    • qmake_unique<int>(99) 创建的智能指针,q.get() 获取的指针在 some_fct() 结束时无效。
    • std::unique_ptr 在函数返回时析构,导致 t3 访问无效内存。
  3. t2(f, &glob);

    • 由于 glob 是全局变量,它的生命周期足够长,可以安全地被 t2 访问。

三:解决方案

        如何避免线程detach后的空悬指针和未定义行为?有以下两种方案:

        1. 只使用全局变量或堆分配的对象

#include <iostream>
#include <thread>
#include <memory>

void f(int* p) {
    *p = 99;
}

int glob = 33;

void some_fct(int* p) {
    auto q = new int(99);   // 使用堆对象
    std::thread t1(f, &glob);  // OK,全局变量
    std::thread t2(f, q);      // OK,堆上分配的对象

    t1.detach();
    t2.detach();

    // 需要手动释放 q,避免内存泄漏
    delete q;
}

       2. 避免 detach(),使用 std::thread::join()joining_thread

void some_fct() {
    int x = 77;
    std::thread t(f, &x);  // OK,因为 t.join() 之前 x 一直有效
    t.join();              // 等待线程结束,确保不会访问销毁的对象
}
class joining_thread {
    std::thread t;
public:
    template <typename... Args>
    explicit joining_thread(Args&&... args) : t(std::forward<Args>(args)...) {}

    ~joining_thread() {
        if (t.joinable()) {
            t.join();
        }
    }
};

void some_fct() {
    int x = 77;
    joining_thread t(f, &x);  //  OK
}


http://www.kler.cn/a/568617.html

相关文章:

  • leetcode第77题组合
  • next.js-学习4
  • 蓝桥杯 6.数学
  • 基于springboot+vue的线上考试系统的设计与实现
  • 在 Ubuntu 下通过 Docker 部署 Caddy 和 PHP-FPM 服务器
  • Java—锁—等待唤醒机制
  • 随机树算法 自动驾驶汽车的路径规划 静态障碍物(Matlab)
  • thinkphp6-使用psubscribe进行redis的注意callback中使用redis
  • 《Python实战进阶》No 11:微服务架构设计与 Python 实现
  • 字符串的最大公因子<枚举>
  • C语言学习笔记-初阶(23)函数详解
  • QT——c++界面编程库
  • app项目管理, 应该以UI为导向还是以研发为导向
  • 细说 Java 集合之 Map
  • 千峰React:组件与逻辑封装(上)
  • 2025国家护网HVV高频面试题总结来了01(题目+回答)
  • Django模型管理器/QuerySet 常见的方法
  • Python基于交互注意力的深度时空网络融合多源信息的剩余寿命预测方法
  • DeepSeek-R1私有化部署——使用Python实现DeepSeek-R1-Distill-Qwen模型部署调用与流式输出
  • 青海高校迎新系统的实施与影响