Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/146.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 析构函数是';t调用所有线程\u本地对象_C++_Multithreading_Gcc_Openmp - Fatal编程技术网

C++ 析构函数是';t调用所有线程\u本地对象

C++ 析构函数是';t调用所有线程\u本地对象,c++,multithreading,gcc,openmp,C++,Multithreading,Gcc,Openmp,我在GCC 6.2.0和C++1z下使用OpenMP。我尝试使用thread\u local对象,这些对象在需要时在线程内部创建thread\u local对象几乎可以正常工作,但似乎只为一个线程调用析构函数。我可以用下面的代码模拟这个问题。代码是否使用了一些不允许的特性,或者GCC实现是否存在一些问题 #include <iostream> #include <memory> #include <mutex> #include <thread>

我在GCC 6.2.0和C++1z下使用OpenMP。我尝试使用
thread\u local
对象,这些对象在需要时在线程内部创建
thread\u 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;
}
程序的输出如下所示:

$ 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

显然只有一个析构函数。< /P> < P>混合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) {
static std::unique_ptr ptr;
#pragma-omp并行
{
ptr.reset();
#pragma omp for
用于(无符号x=0;x<32;++x){

请注意,
reset
是必需的,否则
ptr
的值是未定义的。您不能使用
firstprivate
,因为
std::unique\u ptr
没有复制构造函数。

调用了多少构造函数?线程本地池和线程池肯定会造成内存泄漏和其他有趣的问题。OpenMP有自己的mea使用
#pragma omp threadlocal(…)
声明线程局部变量的数量。通常(但不总是!)与语言构造兼容的实现,例如使用相同的TLS机制,但语义不同。不要混合OpenMP和C++线程。BTW,您是否尝试用“代码> STD::线程< /代码>运行相同的代码?根本不调用析构函数。在OpenMP情况下,线程0是主线程,因此您得到了析构函数。GCC使用ELF TLS实现线程局部变量,就我所知,它没有(或者至少过去没有)支持构造函数和析构函数,因此GCC只允许POD作为线程局部变量。这在GCC的OpenMP
threadprivate
中公开-如果您尝试类似于
#pragma omp threadprivate(ptr)的操作
而不是
thread\u local
,GCC抛出一个错误。Hristo,你是对的。对于std::thread,它也不调用析构函数,只调用构造函数。。。