- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我在 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/
我想知道以下两个声明之间的区别是什么,如果两者都写在一个头文件中: inline thread_local MyClass obj1; // inline with thread_local thr
“所有具有线程局部存储持续时间的非局部变量都作为线程启动的一部分进行初始化,在线程函数开始执行之前进行排序。” ( https://en.cppreference.com/w/cpp/language
我在文件 tracker.hpp 中有一个变量: namespace TRIALS { static thread_local int a = -1; } 我在 ema.hpp/ema.cpp
我认为如果函数不修改非本地数据,它们就是线程安全的。 根据这个answer,我的假设是正确的.但是,最近我遇到了这段代码, int intRand(const int & min, const int
我在销毁 thread_local 静态对象时遇到问题。 #include #include struct UsesLoc { UsesLoc() { loc.counte
我认为如果函数不修改非本地数据,它们就是线程安全的。 根据这个answer,我的假设是正确的.但是,最近我遇到了这段代码, int intRand(const int & min, const int
在我的代码中使用 thread_local 之前,我想更好地理解它。 比方说,我声明 thread_local myclass value; 这将为每个使用 myclass 的线程创建 value 的
C.h: #include class C { public: explicit C(int id) { std::cout<<"Initialized "<
我知道这是一个非常基本的问题,但我找不到简单的答案。 我正在编写一个程序,其中我需要一些变量是 thread_local。根据我的理解,这意味着这些变量“像全局变量”,但每个线程都有自己的拷贝。 我以
在问题Using QSqlQuery from multiple threads结果是线程存储解决了这个问题。 我制作了一个简单的演示代码,以绝对清楚 C++11 thread_local 说明符。下
我有以下 thread_local 单例代码: struct Singl { int& ref; Singl(int& r) : ref(r) {} ~Singl() {} void
我想了解 thread_local 限定符究竟是如何工作的,以及实际变量存储在哪里?这是在 C++ 上。 假设我有一个包含多个成员变量的类。该类的对象在堆上实例化,该对象在 2 个线程之间共享。使用适
#include #include #include using namespace std; struct A { ~A() { cout << "~A()"
现在 C++ 正在添加 thread_local 存储作为语言功能,我想知道一些事情: thead_local 的成本可能是多少? 在内存中? 用于读写操作? 与此相关:操作系统通常如何实现这一点?似
考虑以下示例(为简单起见,省略了 cout 上的锁守卫)。 #include #include #include using namespace std; struct C { C() {
我正在努力解决 C++ Crash Course我遇到了以下代码 list : #include struct Tracer { Tracer(const char* name) :
我想在我的类中进行一些线程注册,因此我决定添加对 thread_local 功能的检查: #include #include class Foo { public: Foo() {
下面的代码应该初始化一个静态线程局部和静态结构。 #include struct Tracer { public: Tracer(const char *new_name) : name{new
我有一个我想构造的类成员,它应该是访问它的每个线程的本地成员。虽然构造函数需要一些参数,所以我不能依赖静态零初始化。 class ThreadMem{ public: ThreadMem(ui
我试图声明 thread_local 指针变量,然后在一个线程中指向一个新对象。 thread_local static A* s_a = nullptr; 好像线程销毁的时候新对象的内存没有释放。我
我是一名优秀的程序员,十分优秀!