OMP线程私有对象不被销毁 [英] OMP threadprivate objects not being destructed

查看:361
本文介绍了OMP线程私有对象不被销毁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

底线



如何确保threadprivate实例被正确销毁?



/ h2>

回答这个问题在VS2013中使用Intel C ++ 15.0编译器时,我遇到了一个奇怪的问题。当声明一个全局变量 threadprivate 时,从线程副本不被销毁。我开始寻找办法强迫他们的毁灭。在网站上,他们表示添加OMP屏障应该有所帮助。它不(见MCVE)。我试图将OMP blocktime设置为0,以便线程不应该坚持后的并行区域(也没有帮助)。我试着添加一些虚拟计算,延迟主线程,给其他线程时间死。仍然没有帮助。



MCVE:



  #include< ; iostream> 
#include< omp.h>

class myclass {
int _n;
public:
myclass(int n):_n(n){std :: cout< int c'tor\\\
; }

myclass():_n(0){std :: cout< def c'tor\\\
; }

myclass(const myclass& other):_n(other._n)
{std :: cout< copy c'tor\\\
; }

〜myclass(){std :: cout< bye bye\\\
; }

void print(){std :: cout< _n<< \\\
; }

void add(int t){_n + = t; }
};

myclass globalClass;
#pragma omp threadprivate(globalClass)

int main(int argc,char * argv [])
{
std :: cout< \\\
Begninning main()\\\
;

//立即停止线程
kmp_set_blocktime(0);

#pragma omp parallel
{
globalClass.add(omp_get_thread_num());
globalClass.print();
#pragma omp barrier
// Barrier不帮助
}

//尝试一些繁忙的工作,需要几秒钟
double dummy = 0.0;
for(int i = 0; i <199999999; i ++)
{
dummy + =(sin(i + 0.1));
}
std :: cout<< dummy<< \\\
;

std :: cout<< 退出main()\\\
;
return 0;
}

输出为



< blockquote>

def c'tor



Begninning main()

def c'tor

1

def c'tor

3

def c'tor

2

0

1.78691

退出main()

bye bye




更新



正在关注 Oyle 4.0标准的Kyle's 报价其中


根据如何在基本语言中处理静态变量,但在程序中未指定的点处,释放threadprivate变量的所有副本的存储。


我添加了一个类的静态实例(全局和本地),看看它的析构函数是否被调用。它是,对于本地和全球的情况。

解决方案

这是记录的行为(虽然我不知道为什么做这个决定) p>

MSDN条目 threadprivate (有一些格式变化):


A threadprivate 可破坏类型的变量不能保证调用其析构函数。



...



用户没有控制,构成并行区域的线程何时终止。如果进程退出时这些线程存在,线程将不会被通知有关进程退出,并且析构函数不会在除了退出的线程(这里是主线程)之外的任何线程上被调用。因此代码不应该计入对 threadprivate 变量的适当销毁。


OpenMP 4.0版标准会将未指定的析构函数调用行为顺序。从 12.14.2 部分:




线程私有变量的所有副本的存储是根据静态变量在基本语言中的处理方式来释放的,但是在程序中未指定的位置。



第152页第8-10行:



类型的threadprivate变量被调用是未指定的。


个人而言,在我看来,微软可能把这个作为太多的空白支票;析构函数未指定与未能保证完全不同,将会调用析构函数。静态变量在基本语言(在这种情况下为C ++)中的处理方式是,析构函数被保证被调用。所以我认为MSVC是不合格的(对于C ++标准和OMP标准),但因为我不是一个语言律师,不要采取我的话。



<有了这个说法,很难看到这可能有严重的影响。你当然不应该看到任何内存泄漏,因为 threadprivate 存储空间应该在创建/销毁线程时立即分配/取消分配。 (如果你的 threadprivate 实例引用了他们管理的非 - threadprivate 内存, t似乎它会工作在第一位。)


Bottom line

How can I make sure that the threadprivate instances are properly destructed?

Background

When answering this question I came across an oddity when using the Intel C++ 15.0 compiler in VS2013. When declaring a global variable threadprivate the slave threads copies are not destructed. I started looking for ways to force their destruction. At this site, they say that adding an OMP barrier should help. It doesn't (see MCVE). I tried setting the OMP blocktime to 0 so that the threads should not stick around after the parallel region (also, didn't help). I tried adding some dummy calculations that delay the main thread, giving the other threads time to die. Still didn't help.

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;
}

The output is

def c'tor

Begninning main()
def c'tor
1
def c'tor
3
def c'tor
2
0
1.78691
Exiting main()
bye bye

There is only one "bye bye" where I would have expected four.

Update

Following Kyle's quote of the OMP 4.0 standard where it states

The storage of all copies of a threadprivate variable is freed according to how static variables are handled in the base language, but at an unspecified point in the program.

I added a static instance of the class (both global and local) to see if its destructor gets called. It does, both for the local and the global case. So the question still stands.

解决方案

This is documented behavior (though I have no idea why this decision was made).

From the MSDN entry on threadprivate (with some formatting changes):

A threadprivate variable of a destructable type is not guaranteed to have its destructor called.

...

Users have no control as to when the threads constituting the parallel region will terminate. If those threads exist when the process exits, the threads will not be notified about the process exit, and the destructor will not be called for threaded_var on any thread except the one that exits (here, the primary thread). So code should not count on proper destruction of threadprivate variables.

The OpenMP version 4.0 standard leaves the order of destructor-call behavior unspecified. From section 12.14.2:

Page 151, lines 7-9:

The storage of all copies of a threadprivate variable is freed according to how static variables are handled in the base language, but at an unspecified point in the program.

Page 152, lines 8-10:

The order in which any constructors for different threadprivate variables of class type are called is unspecified. The order in which any destructors for different threadprivate C++ variables of class type are called is unspecified.

Personally, it seems to me that Microsoft may be taking this as too much of a blank check; destructor order being unspecified seems substantially different from failing to guarantee at all that a destructor will be called. The way static variables are handled in the base language (C++ in this case) is that destructors are guaranteed to be called. So I think MSVC is nonconforming (to both the C++ standard and the OMP standard), but since I'm not a language lawyer, don't take my word for it.

With that said, it's hard to see how this could have serious repercussions. You certainly should not see any memory leaks, since threadprivate storage space should be allocated/deallocated all at once when the thread is created/destroyed. (And if your threadprivate instances have references to non-threadprivate memory that they manage, well...that doesn't seem like it will work in the first place.)

这篇关于OMP线程私有对象不被销毁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆