底线
如何确保 threadprivate 实例被正确销毁?
背景
接听时这个问题 https://stackoverflow.com/questions/32347008/confused-about-firstprivate-and-threadprivate-in-openmp-context/32347782?noredirect=1#comment52589019_32347782我在 VS2013 中使用 Intel C++ 15.0 编译器时遇到了一个奇怪的问题。声明全局变量时threadprivate
从属线程副本不会被破坏。我开始寻找强制摧毁它们的方法。在this http://www.viva64.com/en/a/0054/#ID0EWRDM网站上,他们说添加 OMP 屏障应该会有所帮助。事实并非如此(参见 MCVE)。我尝试将 OMP 阻塞时间设置为 0,以便线程不会在并行区域之后停留(也没有帮助)。我尝试添加一些虚拟计算来延迟主线程,从而给其他线程时间来终止。还是没有帮助。
MCVE:
#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;
}
输出是
定义
开始 main()
定义
1
定义
3
定义
2
0
1.78691
退出 main()
bye bye
我本以为有四个“再见”,但只有一个。
Update
下列的Kyle's https://stackoverflow.com/a/32383184/2899559引用 OMP 4.0 标准,其中指出
线程私有变量的所有副本的存储根据静态变量在基本语言中的处理方式被释放,但在程序中的未指定点。
我添加了该类的静态实例(全局和本地)以查看其析构函数是否被调用。对于本地和全球情况来说都是如此。所以问题仍然存在。
这是有记录的行为(尽管我不知道为什么做出这个决定)。
来自MSDN 条目位于threadprivate https://msdn.microsoft.com/en-US/library/2z1788dd.aspx(有一些格式更改):
A threadprivate
不保证可破坏类型的变量会调用其析构函数。
...
用户无法控制至于构成并行区域的线程何时终止。如果进程退出时这些线程存在,则线程将不会收到有关进程退出的通知,并且除了退出的线程(此处为主线程)之外的任何线程上都不会为 threaded_var 调用析构函数。所以代码不应依赖于适当的破坏threadprivate
变量。
The OpenMP 4.0 版标准 http://www.openmp.org/mp-documents/OpenMP4.0.0.pdf留下order of未指定析构函数调用行为。来自部分12.14.2:
第 151 页,第 7-9 行:
线程私有变量的所有副本的存储根据静态变量在基本语言中的处理方式被释放,但在程序中的未指定点。
第 152 页,第 8-10 行:
类类型的不同 threadprivate 变量的任何构造函数的调用顺序是未指定的。类类型的不同 threadprivate C++ 变量的任何析构函数的调用顺序是未指定的。
就我个人而言,在我看来,微软可能认为这太过分了。析构函数order未指定似乎与未能保证有很大不同at all将调用析构函数。在基本语言(本例中为 C++)中处理静态变量的方式是析构函数保证被称为。所以我认为 MSVC 不符合(不符合 C++ 标准和 OMP 标准),但由于我不是语言律师,所以不要相信我的话。
话虽如此,很难看出这会如何产生严重影响。您当然不应该看到任何内存泄漏,因为threadprivate
当线程创建/销毁时,应立即分配/释放存储空间。 (如果你的threadprivate
实例引用了非threadprivate
他们管理的内存,嗯……这似乎一开始就不起作用。)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)