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

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
}

相关文章:

  • JavaScript异步处理确保排序不乱的方案
  • 16981等腰三角形
  • Difyにboto3を変更したカスタムDockerイメージの構築手順
  • Java 8 新特性
  • 2024蓝桥杯省赛真题-封闭图形个数
  • 蓝桥杯备考:从记忆化搜索到动态规划
  • 深入解析 Spring WebFlux:原理与应用
  • 链表OJ(十二)23. 合并 K 个升序链表 困难 优先级队列中存放指针结点
  • 什么是预训练语言模型下游任务?
  • 16.3 LangChain Runnable 协议精要:构建高效大模型应用的核心基石
  • LeetCode 27 移除元素
  • Linux(centOS) 命令提示符格式修改(PS1)
  • 数据结构(初阶)(七)----树和二叉树(堆,堆排序)
  • linux基础知识
  • RFID工具柜DW-G104R|智能存储,便捷高效
  • 解决git add . + git commit之后文件状态还是M 问题
  • java后端开发day25--阶段项目(二)
  • 《今日AI-编程-人工智能日报》
  • 130. 被围绕的区域(BFS)
  • 如何利用SpringSecurity进行认证与授权
  • 演员朱媛媛去世,其丈夫辛柏青发讣告
  • 在越剧之乡嵊州,浙江音乐学院越剧学院成立
  • 天问二号探测器顺利转入发射区
  • 广西鹿寨一水文站“倒刺扶手”存安全隐患,官方通报处理情况
  • 上海制造佳品汇大阪站即将启幕,泡泡玛特领潮出海
  • 诠释微末处的丰盈:“上海制造佳品汇”首届海外专场即将亮相日本大阪