thread_local unique_ptr<class>应该如何使用来防止内存泄漏

问题描述 投票:0回答:1

一位同事写道:

namespace {
    thread_local constinit int lastY = -1;
    thread_local std::unique_ptr<AvxBezierAndSaturation> pAvxBezierAndSaturation{};
}

void Class::functionName(....)
{
  :
        if (!static_cast<bool>(pAvxBezierAndSaturation))
            pAvxBezierAndSaturation = std::make_unique<AvxBezierAndSaturation>(bufferLen);
 
}

当程序终止 AvxBezierAndSaturation 的所有实例时,VLD 会将其分配的存储报告为存储泄漏。

这是 thread_local unique_ptr 的正确用法吗?如果不是,应该如何使用?

谢谢 大卫

c++ unique-ptr thread-local
1个回答
0
投票

最可能的问题可能是程序退出时并非所有线程都已终止。
鉴于您正在使用 openmp,这些很可能属于 openmp。


1. C++ 标准

标准中有两种情况可以结束

thread_local
变量的生命周期:

  • 线程从其初始函数返回
  • std::exit()
    被称为
    这将销毁调用
    thread_local
    的线程的所有
    std::exit
    变量。
    但不适用于除了调用
    std::exit
    的线程之外可能仍在运行的任何其他线程。
    注:从
    main()
    回来会为您打电话
    std::exit()

这包括:

6.9.3.4 程序执行 - 启动和终止 [basic.start.term] [强调我的]

(2) 给定线程内具有线程存储持续时间的构造对象将由于 从该线程的初始函数返回以及由于 该线程调用

std​::​exit
而被销毁。在销毁任何具有静态存储持续时间的对象之前,该线程内所有具有线程存储持续时间的构造对象的销毁都会发生。

17.5 启动和终止 [support.start.term] [强调我的]

[[noreturn]] void exit(int status);

(9) 效果:
(9.1) - 首先,具有线程存储持续时间且与当前线程关联的对象被销毁。接下来,具有静态存储持续时间的对象被销毁,并调用通过调用atexit注册的函数。 [...]

因此,只要确保在调用

std::exit
时没有其他线程正在运行(通过从
main()
返回隐式或显式),那么所有
thread_local
变量都应该被正确清理。


2. MSVC + openmp

假设您正在使用 msvc 和 openmp,因为您正在使用 vld(并在评论中提到了 openmp)。

OpenMP 不是 C++ 标准的一部分,因此规则可能略有不同。

MSVC 的 OpenMP 文档包含以下段落:
(注意openmp

threadprivate
__declspec(thread)
thread_local
在msvc中都是一样的)

OpenMP 库参考 - 指令 - threadprivate

线程私有

备注

[...]
不保证可破坏类型的 threadprivate 变量会调用其析构函数。
[...]
用户无法控制构成并行区域的线程何时终止。如果进程退出时这些线程存在,则线程不会收到有关进程退出的通知,并且除了退出的线程(此处为主线程)之外的任何线程上都不会为 threaded_var 调用析构函数。因此,代码不应依赖于正确销毁 threadprivate 变量。

即如果您使用 openmp,则不能保证会调用

thread_local
变量的析构函数。

© www.soinside.com 2019 - 2024. All rights reserved.