Ich arbeite mit OpenMP unter GCC 6.2.0 und C++ 1z. Ich habe versucht, thread_local
Objekte zu verwenden, die in Threads erstellt werden, wenn sie benötigt werden. thread_local
Objekte funktionieren fast gut, aber es scheint, dass Destruktoren nur für einen Thread aufgerufen werden. Ich kann das Problem mit dem folgenden Code simulieren. Verwendet der Code ein nicht zugelassenes Feature oder besteht möglicherweise ein Problem mit der GCC-Implementierung?Destruktor wird nicht für alle thread_local Objekte aufgerufen
#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 ist kompiliert und unter Linux mit 4-Core-i7-CPU bauen. Befehle für die Erstellung sehen so aus:
$ 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
Ausgabe des Programms sieht so aus:
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
Offensichtlich nur eine destructor genannt wird.
Wie viele Konstruktoren werden aufgerufen? –
Thread lokalen und Thread-Pools ist eine todsichere Möglichkeit, Speicherlecks und andere Spaß Probleme zu erstellen. – Voo
OpenMP hat seine eigene Möglichkeit, threadlokale Variablen mit '#pragma omp threadlocal (...)' zu deklarieren. Es ist oft (aber nicht immer) implementierungskompatibel mit den Sprachkonstrukten, z. B. wird derselbe TLS-Mechanismus verwendet, aber die Semantik unterscheidet sich. Mischen Sie nicht OpenMP und C++ - Threading! –