gpt4 book ai didi

c++ - 不会为所有 thread_local 对象调用析构函数

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:44:35 24 4
gpt4 key购买 nike

我在 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 的定义不明确。 (参见 related questions )。基本上 OpenMP 仅指 C++98,因此与 OpenMP 和 threadlocal 的交互是不安全/可移植的。通常假设它会工作,因为实现做了正确的事情,但在这种情况下显然他们没有。顺便说一句:我可以使用英特尔编译器/OpenMP 运行时重现同样的问题。

安全且可移植的方法是坚持使用纯 C++17 或 OpenMP。对于 OpenMP,这意味着将 ptr 定义为私有(private):

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 没有复制构造器。

关于c++ - 不会为所有 thread_local 对象调用析构函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41592148/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com