如何确保正确销毁threadprivate实例?
在回答this question时,我在VS2013中使用英特尔C ++ 15.0编译器时遇到了一个奇怪的现象。声明全局变量threadprivate
时,从属线程副本不会被破坏。我开始寻找迫使他们毁灭的方法。在this网站,他们说添加OMP屏障应该会有所帮助。它没有(见MCVE)。我尝试将OMP阻塞时间设置为0,以便线程不应该在并行区域之后(也没有帮助)。我尝试添加一些延迟主线程的虚拟计算,让其他线程有时间死掉。仍然没有帮助。
#include <iostream>
#include <omp.h>
class myclass {
int _n;
public:
myclass(int n) : _n(n) { std::cout << "int c'tor\n"; }
myclass() : _n(0) { std::cout << "def c'tor\n"; }
myclass(const myclass & other) : _n(other._n)
{ std::cout << "copy c'tor\n"; }
~myclass() { std::cout << "bye bye\n"; }
void print() { std::cout << _n << "\n"; }
void add(int t) { _n += t; }
};
myclass globalClass;
#pragma omp threadprivate (globalClass)
int main(int argc, char* argv[])
{
std::cout << "\nBegninning main()\n";
// Kill the threads immediately
kmp_set_blocktime(0);
#pragma omp parallel
{
globalClass.add(omp_get_thread_num());
globalClass.print();
#pragma omp barrier
//Barrier doesn't help
}
// Try some busy work, takes a few seconds
double dummy = 0.0;
for (int i = 0; i < 199999999; i++)
{
dummy += (sin(i + 0.1));
}
std::cout << dummy << "\n";
std::cout << "Exiting main()\n";
return 0;
}
输出
def c&#39; tor
begninning main()
def c&#39; tor 1
def c&#39; tor 3
def c&#39; tor 2
0
1.78691
退出main()
再见
只有一个&#34;再见&#34;我原本预计会有四个人。
在{OMP 4.0标准的Kyle's引用之后
根据在基本语言中处理静态变量的方式,但是在程序中未指定的点处,释放了threadprivate变量的所有副本的存储。
我添加了一个类的静态实例(全局和本地),以查看它的析构函数是否被调用。它确实适用于本地和全球案例。所以问题仍然存在。
答案 0 :(得分:3)
这是记录在案的行为(虽然我不知道为什么做出这个决定)。
来自MSDN entry on threadprivate
(进行了一些格式更改):
无法保证可破坏类型的
threadprivate
变量的析构函数被调用。...
用户无法控制何时构成并行区域的线程将终止。如果进程退出时存在这些线程,则不会通知线程进程退出,并且除了退出的线程(此处为主线程)之外,不会在任何线程上为thread_var调用析构函数。因此,代码不应指望
threadprivate
变量的正确销毁。
OpenMP version 4.0 standard未指定析构函数调用行为的顺序。来自 12.14.2 :
部分第151页,第7-9行:
根据在基本语言中处理静态变量的方式,但是在程序中未指定的点处,释放了threadprivate变量的所有副本的存储。
第152页,第8-10行:
未指定调用类类型的不同threadprivate变量的任何构造函数的顺序。调用类型的不同threadprivate C ++变量的任何析构函数的顺序是未指定的。
就我个人而言,在我看来,微软可能会将此视为过多的空白支票;析构函数 order 未指定似乎与未能保证在所有中调用析构函数有很大不同。在基本语言中处理静态变量的方式(在本例中为C ++)是析构函数保证被调用。所以我认为MSVC不符合(对C ++标准和OMP标准),但由于我不是语言律师,所以不要相信我的话。
话虽如此,很难看出这会产生怎样的严重后果。您当然不应该看到任何内存泄漏,因为在创建/销毁线程时,应该同时分配/解除分配threadprivate
存储空间。 (如果你的threadprivate
个实例引用了他们管理的非threadprivate
内存,那么......这似乎不会起作用。)