Tryer
Tryer

Reputation: 4050

OpenMP Parallelization of sequential functions that are not within a for loop

GlobalDefines.h has the following #defined

#define FOO_1 true//true if function void foo1() should run, false otherwise
#define FOO_2 false//true if function void foo2() should run, false otherwise

Within src.cpp, these are used thus:

#include GlobalDefines.h

class BigClassX{
    std::vector<int>...;
    ....
};

BigClassX ObjX;

int main(){

    #if FOO_1
       foo1(objX);
    #if FOO_2
       foo2(objX);

}

foo1 (likewise foo2) takes in its argument by reference thus:

void foo1(class BigClassX& objX){}

I would like to parallelize foo1 and foo2 even though they are not in a for loop.

My attempt was the following and it seems a bit roundabout in that I explicitly have to introduce a for loop:

#pragma omp parallel for
for(int i = 1; i <= 2; i++)
    foox(i, objX);

Now, foox is thus:

void foox(int indicator, class BigClassX& objX){
    if(FOO_1 && indicator == 1)
        foo1(objX);
    if(FOO_2 && indicator == 2)
        foo2(objX);
}

Is there any other way to parallelize this within OpenMP? My concerns with the above method are:

(1)Is there any performance hit with passing around big object objX by reference across OpenMP parallel for construct? Since it is a big object, I anyways pass it by reference, but is there anything in particular I should be worried about when placing that within an OpenMP parallel for construct?

(2)As indicated above, it seems a bit round about since I am having to introduce a new function foox and within foox I have to check which function to call based on the indicator.

Upvotes: 0

Views: 44

Answers (1)

Zulan
Zulan

Reputation: 22660

1. Don't abuse the preprocessor like this.

Just don't - unless it is absolutely unavoidable. Besides your example is missing #endif. You will burn yourself or others with this, you will suffer. Instead of use if constexpr - or just a regular if on a const or constexpr. This is fine.

2. This is a use case for OpenMP sections

Your code looks like

#pragma omp parallel sections
{
    #pragma omp section
    {
        foo1(objX);
    }
    #pragma omp section
    {
        foo2(objX);
    }
}

3. Avoid race conditions

In general, this object is shared between the sections and the same reference is passed to foo1 and foo2. Working on shared objects in parallel is dangerous. You must avoid any access to the same leaf elements (individual values) within objX unless all sections only read.

Depending on your specific case you can use atomic operations or critical sections to protect against race conditions.

Upvotes: 1

Related Questions