2wings
2wings

Reputation: 71

openMP C++ error with threadprivate vector

#include<iostream>
#include<vector>
#include<ctime>
#include<cmath>
#include<omp.h>
#include<array>
using namespace std;

double counter = 0;
vector<int> vec;

vector<double> reduction;
#pragma omp threadprivate(reduction)


vector<double> eet;
int fish;


void mario( int current_node, int current_depth) {
    int q = current_node % 4;
    #pragma omp simd
    for( int i = 3 ; i < current_node; i+=4){
        reduction[i]+=4;
        mario(i, current_depth);
        mario(i - 1,current_depth);
        mario(i - 2,current_depth);
        mario(i - 3,current_depth);
    }
    #pragma omp simd
    for(int x = 1; x <= q; x++){
        reduction[0]++;
        mario(current_node - x,current_depth);
    }
    #pragma omp task firstprivate(current_node,current_depth)
    {
        if(current_depth > 0){
                int new_depth = current_depth - 1;
                #pragma omp simd
                for(int i = current_node;i <= vec[current_node];i++){
                    reduction[i]++;
                    mario(i + 1,new_depth);
            }
        } 
    } 
}


int main() {
    omp_proc_bind_true;
    omp_set_dynamic(0);
    int nodes;
    int timesteps;
    int threadz;
    cout << "enter number of nodes" << endl;

    cin >> nodes;

    cout << "enter number of timesteps" << endl;

    cin >> timesteps;

    cout << "enter number threads" << endl;

    cin >> threadz;

    omp_set_num_threads(threadz);

    int mushroom = nodes - 2;
    fish = nodes - 1;

    vec.assign( nodes, mushroom );

    clock_t t = clock();

    vector<double> zed(mushroom + 1 , 0 );

    eet = zed;
    reduction = eet;
    #pragma omp parallel copyin(reduction)
    {

        #pragma omp single
        {
            mario(nodes - 1, timesteps - 1);
        }

        #pragma omp critical
        {
            #pragma omp simd
            for(int x = 0; x < zed.size();x++){
                eet[x] += reduction[x];
            }
        }
        #pragma omp barrier
    }
    for(int j = 0; j < eet.size(); j++){
            counter += eet[j];
    }
    t = clock() - t;
    double time_taken = ((double)t) / CLOCKS_PER_SEC;
    cout << "mario took " << fixed << counter << " steps" << endl;
    cout << "It took him " << time_taken << " seconds" << endl;
    return 0;
}

In my code I declare the vector reduction: vector<double> reduction;

Then I immediately use threadprivate: #pragma omp threadprivate(reduction), but when I compile my code I get the errors.

error: 'reduction' declared 'threadprivate' after first use

13 | #pragma omp threadprivate(reduction)

error: 'reduction' must be 'threadprivate' for 'copyin'

82 | #pragma omp parallel copyin(reduction)

What is causing these errors? I just declared the variable without doing anything else.

Is the error avoidable?

Are there any other methods for reduction across openMP tasks for recursive functions

or alternative methods for combating the problem?

Is there something fundamentally wrong with the way I am trying to write my code?

I am using gcc 9.3

, sorry if my question is unclear please suggest improvements.

Upvotes: 1

Views: 389

Answers (1)

2wings
2wings

Reputation: 71

A bodge of an solution that only works with gcc, it is unfortunately just a workaround and not a proper solution.

#include<iostream>
#include<vector>
#include<ctime>
#include<cmath>
#include<omp.h>
#include<array>
#include<thread>
using namespace std;

double counter = 0;
vector<int> vec;
thread_local vector<double> reduction;

vector<double> eet;
int fish;



void mario( int current_node, int current_depth) {
    int q = current_node % 4;
    #pragma omp simd
    for( int i = 3 ; i < current_node; i+=4){
        reduction[i]+=4;
        mario(i, current_depth);
        mario(i - 1,current_depth);
        mario(i - 2,current_depth);
        mario(i - 3,current_depth);
    }
    #pragma omp simd
    for(int x = 1; x <= q; x++){
        reduction[0]++;
        mario(current_node - x,current_depth);
    }
    #pragma omp task firstprivate(current_node,current_depth)
    {
        if(current_depth > 0){
                int new_depth = current_depth - 1;
                #pragma omp simd
                for(int i = current_node;i <= vec[current_node];i++){
                    reduction[i]++;
                    mario(i + 1,new_depth);
            }
        } 
    } 
}



int main() {
    omp_proc_bind_true;
    omp_set_dynamic(0);
    int nodes;
    int timesteps;
    int threadz;
    cout << "enter number of nodes" << endl;

    cin >> nodes;

    cout << "enter number of timesteps" << endl;

    cin >> timesteps;

    cout << "enter number threads" << endl;

    cin >> threadz;

    omp_set_num_threads(threadz);
    int mushroom = nodes - 2;
    fish = nodes - 1;
    vec.assign( nodes, mushroom );
    clock_t t = clock();
    vector<double> zed(mushroom + 1 , 0 );
    eet = zed;
    #pragma omp parallel
    {
        reduction = zed;
        #pragma omp barrier
        #pragma omp single
        {
            mario(nodes - 1, timesteps - 1);
        }
        #pragma omp critical
        {
            for(int x = 0; x < reduction.size();x++){
                eet[x] += reduction[x];
            }

        }
        #pragma omp barrier
    }
    for(int j = 0; j < eet.size(); j++){
            counter += eet[j];
    }
    t = clock() - t;
    double time_taken = ((double)t) / CLOCKS_PER_SEC;
    cout << "mario took " << fixed << counter << " steps" << endl;
    cout << "It took him " << time_taken << " seconds" << endl;
    return 0;
}

This is a terrible method happens to work, apparently gcc's c++ implementation uses POSIX threads and,gcc implementation of openMP is just POSIX under the hood. source: Using C++11 thread_local with other parallel libraries

So with gcc if a variable is sent thread local storage that way it is equivalent to a 'threadprivate' variable to the openMP.

Someone else please suggest a proper solution.

Upvotes: 2

Related Questions