OMP线程私有对象没有被销毁
OMP threadprivate objects not being destructed
底线
我如何确保threadprivate实例被正确地销毁?
的背景在回答这个问题时,我在VS2013中使用英特尔c++ 15.0编译器时遇到了一个奇怪的现象。当声明全局变量threadprivate
时,从线程副本不会被销毁。我开始想办法迫使他们灭亡。在这个地方,他们说添加一个OMP屏障应该会有帮助。它不会(参见MCVE)。我尝试将OMP阻塞时间设置为0,以便线程不应该在并行区域之后停留(也没有帮助)。我尝试添加一些虚拟计算来延迟主线程,让其他线程有时间死亡。还是没用
MCVE:
#include <iostream>
#include <omp.h>
class myclass {
int _n;
public:
myclass(int n) : _n(n) { std::cout << "int c'torn"; }
myclass() : _n(0) { std::cout << "def c'torn"; }
myclass(const myclass & other) : _n(other._n)
{ std::cout << "copy c'torn"; }
~myclass() { std::cout << "bye byen"; }
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 'tor
begin main()
defc 'tor
1
defc 'tor
3
defc 'tor
2
0
1.78691
退出main()
拜拜
只有一个"再见"
更新遵循Kyle对OMP 4.0标准的引用,其中规定
线程私有变量的所有副本的存储空间根据基本语言中静态变量的处理方式被释放,但在程序中未指定的点。
我添加了类的静态实例(包括全局实例和局部实例),以查看它的析构函数是否被调用。确实如此,无论是在本地还是在全球。所以这个问题仍然存在
这是有记录的行为(尽管我不知道为什么做出这个决定)。
来自threadprivate
上的MSDN条目(有一些格式更改):
可析构类型的
threadprivate
变量不能保证其析构函数被调用。…
用户无法控制构成并行区域的线程何时终止。如果进程退出时存在这些线程,则不会通知线程进程退出,并且除了退出的线程(这里是主线程)之外,不会在任何线程上调用threadd_var的析构函数。因此,代码不应该指望
threadprivate
变量的适当销毁。
OpenMP 4.0版标准没有指定析构函数调用行为的顺序。From section 12.14.2:
第151页,第7-9行:
线程私有变量的所有副本的存储空间根据基本语言中静态变量的处理方式被释放,但在程序中未指定的点。
第152页,第8-10行:
类类型的不同线程私有变量的构造函数调用顺序未指定。类类型的不同threadprivate c++变量的析构函数调用顺序未指定。
在我个人看来,微软可能把这当成了一张空白支票;析构函数顺序未指定似乎与根本无法保证将调用析构函数有本质区别。在基本语言(本例中为c++)中处理静态变量的方式是,析构函数保证被调用。所以我认为MSVC不符合(c++标准和OMP标准),但因为我不是语言律师,所以不要相信我的话。
话虽如此,很难看出这可能会产生严重的影响。当然,您不应该看到任何内存泄漏,因为threadprivate
存储空间应该在创建/销毁线程时立即分配/释放。(如果你的threadprivate
实例有引用非threadprivate
内存,他们管理,好吧……这看起来不像它将工作放在首位。)
- 即发即弃 std::线程对象清理自身
- C++:处理线程本地对象销毁
- 结束另一个线程中使用的对象的生存期
- 通过插槽和信号在不同线程中的两个qt对象之间进行通信
- 处理影响跨不同线程共享对象的定时回调的最佳方法是什么?
- 线程调用的函数对对象删除是否安全?
- 将对象传递给多线程对象 Qt
- asio 链对象线程安全吗?
- 如何初始化大线程本地对象?
- 在销毁期间从另一个线程调用对象上调用方法是否未定义行为?
- 当只有一个线程主要使用该对象而其他线程很少使用它时,如何最小化该对象的互斥锁锁定?
- 如何将对象从类线程传递到帖子?
- 将抽象对象从主线程发送到其他线程
- 在 While 循环中重用对象的多线程
- 本地静态函数对象线程安全的初始化
- 对于 c++11 之前的编译器,返回本地静态对象线程是否安全
- 从一个对象线程中使用 const 方法是否安全
- C++流对象线程安全
- 使STL对象线程安全的标准方法
- QT多线程和移动对象线程创建后