并非所有对象都调用析构函数thread_local
Destructor isn't called for all thread_local objects
我在GCC 6.2.0和C++1z下使用OpenMP。我尝试在需要时使用在线程中创建thread_local
对象。 thread_local
对象几乎可以正常工作,但似乎只为一个线程调用析构函数。我可以用以下代码模拟问题。代码是否使用了某些不允许的功能,或者 GCC 实现可能存在一些问题?
#include <iostream>
#include <memory>
#include <mutex>
#include <thread>
#include <sstream>
std::mutex g_cerr_mutex;
struct X {
std::string name_;
X() {
std::stringstream ss;
ss << std::this_thread::get_id();
name_ = ss.str();
}
~X() noexcept {
std::lock_guard<std::mutex> guard(g_cerr_mutex);
std::cerr << "Destructing: " << name_ << std::endl;
}
};
int main(void) {
static thread_local std::unique_ptr<X> ptr;
#pragma omp parallel for
for (unsigned x = 0; x < 32; ++x) {
if (!ptr) {
ptr.reset(new X);
}
std::lock_guard<std::mutex> guard(g_cerr_mutex);
std::cerr << std::this_thread::get_id() << " : " << static_cast<void*>(ptr.get()) << std::endl;
}
return 0;
}
代码是在具有 4 核 i7 CPU 的 Linux 下编译和构建的。用于编译的命令如下所示:
$ g++ -std=gnu++1z -fopenmp -Wall -Werror -Ofast -pthread -c omp.cpp
$ g++ -std=gnu++1z -fopenmp -Wall -Werror -Ofast -pthread omp.o -o omp
程序的输出如下所示:
139868398491392 : 0x7f35780008c0
139868398491392 : 0x7f35780008c0
139868398491392 : 0x7f35780008c0
139868398491392 : 0x7f35780008c0
139868453738496 : 0x7bc2d0
139868453738496 : 0x7bc2d0
139868453738496 : 0x7bc2d0
139868453738496 : 0x7bc2d0
139868423669504 : 0x7f35880008c0
139868423669504 : 0x7f35880008c0
139868423669504 : 0x7f35880008c0
139868423669504 : 0x7f35880008c0
139868406884096 : 0x7f35700008c0
139868406884096 : 0x7f35700008c0
139868406884096 : 0x7f35700008c0
139868406884096 : 0x7f35700008c0
139868432062208 : 0x7f35a00008c0
139868432062208 : 0x7f35a00008c0
139868432062208 : 0x7f35a00008c0
139868432062208 : 0x7f35a00008c0
139868390098688 : 0x7f35900008c0
139868390098688 : 0x7f35900008c0
139868390098688 : 0x7f35900008c0
139868390098688 : 0x7f35900008c0
139868415276800 : 0x7f35980008c0
139868415276800 : 0x7f35980008c0
139868415276800 : 0x7f35980008c0
139868415276800 : 0x7f35980008c0
139868381705984 : 0x7f35800008c0
139868381705984 : 0x7f35800008c0
139868381705984 : 0x7f35800008c0
139868381705984 : 0x7f35800008c0
Destructing: 139868453738496
显然只调用了一个析构函数。
混合C++语言线程功能和 OpenMP 没有明确定义。(请参阅相关问题)。基本上OpenMP仅指C++98,因此与OpenMP和threadlocal
的交互是不安全/可移植的。通常假设它会起作用,因为实现会做正确的事情,但在这种情况下,它们显然没有。 顺便说一句:我可以在英特尔编译器/OpenMP运行时重现相同的问题。
安全和便携的方法是坚持使用纯C++17或OpenMP。使用 OpenMP,这意味着将ptr
定义为私有:
static std::unique_ptr<X> ptr;
#pragma omp parallel
{
ptr.reset();
#pragma omp for
for (unsigned x = 0; x < 32; ++x) {
请注意,reset
是必需的,否则未定义ptr
的值。您不能使用firstprivate
因为std::unique_ptr
没有复制 ctor。
相关文章:
- 什么时候调用组成单元对象的析构函数
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 内联映射初始化的动态atexit析构函数崩溃
- 什么时候调用析构函数
- 优先顺序:智能指针和类析构函数
- C++-明确何时以及如何调用析构函数
- 使用基类指针创建对象时,缺少派生类析构函数
- 在c++中使用向量时,如何调用构造函数和析构函数
- 重载运算符new[]的行为取决于析构函数
- 我需要知道编译器如何在cpp中使用析构函数
- 为什么在使用转换构造函数赋值后调用C++类的析构函数?
- 析构函数调用
- 通过引用传递-为什么要调用这个析构函数
- 对具有动态分配的内存和析构函数的类对象的引用
- 重载 -> shared_ptr 个实例中的箭头运算符<interface>,接口中没有纯虚拟析构函数
- C++成员的析构函数顺序与shared_ptr
- C++ 防止在映射中放置()时调用析构函数
- 使用 boost::thread 运行函子,但析构函数被错误地调用
- std::thread::join 在析构函数中挂起
- 为什么boost::thread的析构函数分离可接合线程,而不是像标准建议的那样调用terminate()