I work with OpenMP under GCC 6.2.0 and C++1z. I tried to use thread_local
objects that are created inside threads when they are needed. thread_local
objects work almost fine but it seems that destructors are called for only one thread. I can simulate the issue with the following code. Is the code using some unallowed feature or is there possibly some issue with the GCC implementation?
#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;
}
Code is compiled and build under linux with 4-core i7 CPU. Commands for the compilation look this way:
$ 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
Output of the programm looks this way:
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
Obviously only one destructor is called.