OpenMp:Threadlocal成员

时间:2014-07-23 09:53:17

标签: c++ openmp

我目前正在研究一位使用OpenMp的前同事编写的代码。然而,我自己对OpenMp没有任何考验,虽然我只是通过阅读他的代码来理解基础知识,但我目前仍在努力弄清楚如何为我自己的修改声明一个threadlocal成员。

非常简化版本中的当前代码如下所示:

struct Worker
{
    void work() { //... }
};

-------------------------------------------------------------------

Worker worker;

#pragma omp parallel for
for (int i = 0; i < n; ++i)
{
    worker.work();
}

我想要实现的是以与此类似的方式修改Worker类:

struct Worker
{
    void work() { // m_var is accessed here }

    int m_var; // should be threadlocal
};

但是我不知道如何使用OpenMP实现这一目标。请注意,Worker中的所有其他成员不应该是同步的,也不应该是threadlocal。

PS:对于那些好奇的人来说,Worker实际上是一个下载一些复杂内容的类,而在for循环中则执行单个下载。 m_var将成为持有会话的对象。

2 个答案:

答案 0 :(得分:3)

非静态数据成员在类的每个实例中都有单独的实例,并且不能是线程本地的 - 它们继承给定类的具体对象的共享类。例如,如果在OpenMP线程的堆栈上创建了类Worker的对象(即该对象具有自动存储类),则该对象本身对该线程是私有的,worker.m_var也是私人的。如果在堆上创建对象,则可以与其他线程共享,然后也将共享worker->m_var

Thread-private只能应用于具有静态存储类的数据成员:

struct Worker
{
    void work();

    static int m_var;
    #pragma omp threadprivate(m_var)
};

int Worker::m_var;

在这种情况下,只存在Worker::m_var的一个静态(全局)副本,并使其成为线程私有,为每个线程提供在该线程中Worker的所有实例之间共享的单独实例。

另请注意,privatefirstprivate无法应用于班级数据成员,无论他们是否为静态 - 请参阅this answer

答案 1 :(得分:0)

如果static要求对于您的情况不可接受,则可以用自己的类替换int字段-该类可以是您的Worker专用的,或者您可以将其作为模板,以供不同类中的不同字段重用。

无论哪种方式,只要有OpenMP线程(我们将其称为int_array),新类的构造函数都会分配一个数组

    ThreadedInt() {
        int_array = new int[omp_get_max_threads()];
    }

您还将实现将这个新类转换为原始类型(在您的示例中为int时所必需的 operators )。例如:

    operator int() const {
        return int_array[omp_get_thread_num()];
    }

以及其他一些内容,例如作业:

    int& operator = (int value) {
        return int_array[omp_get_thread_num()] = value;
    }

然后,其余代码可以保持不变,无论是否为OpenMP。