Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define a object or struct as threadprivate in OpenMP?

I don't know how to make a struct or object as threadprivate, what I'm doing generates a error:

    struct point2d{
        int x;
        int y;
        point2d(){
            x = 0;
            y = 0;
        }
        //copy constructor
        point2d(point2d& p){
            x = p.x;
            y = p.y;
        }
    };      

I declare a static structure and try to make them threadprivate

    static  point2d myPoint;
    #pragma omp threadprivate(myPoint)

It generates an error:

error C3057: 'myPoint' : dynamic initialization of 'threadprivate' symbols is not currently supported

Does it means that current openmp compiler doesn't support this to make a struct threadprivate? Or what I'm doing is wrong. Is there any alternate way to pass a struct or object?

Here's rest part of my codes:

    void myfunc(){
        printf("myPoint at %p\n",&myPoint);
    }

    void main(){
    #pragma omp parallel
       {
           printf("myPoint at %p\n",&myPoint);
           myfunc();
       }

    }
like image 859
Charles Chow Avatar asked May 08 '14 20:05

Charles Chow


2 Answers

In C++ a struct with methods is a Class where the default is public. It's not plain-old-data (POD). MSVC seems to imply that it can handle threadprivate objects (i.e. non-POD) but I can't seem to get it to work. I did get it working in GCC like this:

extern point2d myPoint;
#pragma omp threadprivate(myPoint)
point2d myPoint;

But there is a work around which will work with MSVC (as well as GCC and ICC). You can use threadprivate pointers.

The purpuse of threadprivate is to have private version of an object/type for each thread and have the values persistent between parallel regions. You can do that by delcaring a pointer to point2d, making that threadprivate, and then allocating memory for the private pointer for each thread in a parallel region. Make sure you delete the allocated memory at your last parallel call.

#include <stdio.h>
#include <omp.h>

struct point2d {
    int x;
    int y;
    point2d(){
        x = 0;
        y = 0;
    }
    //copy constructor
    point2d(point2d& p){
        x = p.x;
        y = p.y;
    }
};      

static point2d *myPoint;
#pragma omp threadprivate(myPoint)

int main() {

    #pragma omp parallel 
    {
        myPoint = new point2d();
        myPoint->x = omp_get_thread_num();
        myPoint->y = omp_get_thread_num()*10;
        #pragma omp critical
        {
            printf("thread %d myPoint->x %d myPoint->y %d\n", omp_get_thread_num(),myPoint->x, myPoint->y);
        }
    }   
    #pragma omp parallel
    {
        #pragma omp critical
        {
            printf("thread %d myPoint->x %d myPoint->y %d\n", omp_get_thread_num(),myPoint->x, myPoint->y);
        }
        delete myPoint;
    }
}
like image 179
Z boson Avatar answered Sep 25 '22 02:09

Z boson


What you do in your code is completely correct. Quoting the OpenMP standard (emphasis mine):

A threadprivate variable with class type must have:

  • an accessible, unambiguous default constructor in case of default initialization without a given initializer;
  • an accessible, unambiguous constructor accepting the given argument in case of direct initialization;
  • an accessible, unambiguous copy constructor in case of copy initialization with an explicit initializer.

The one in bold seems exactly your case.

The behavior you encounter seems a missing feature or a bug in the compiler. Strangely enough, even GCC seems to have problem with that, while Intel is claimed to work fine.

like image 36
Massimiliano Avatar answered Sep 25 '22 02:09

Massimiliano