Search code examples
c++thread-safetyopenmppragma

How to make this code thread safe with openMP?


The schematic code shown below works fine if I remove the #pragma omp parallel for, but with this in place the code compiles but then upon executing the binary I get errors like *** glibc detected *** ./testBin: double free or corruption (!prev): 0x0c43d8d8 *** and core dumped. I'm guessing that the reason is that multiple threads try to write to the variables omega, ell, .... or lineVec. How do I fix this? Is there a way to tell it the variables are shared? or is there just generally another way to do this loop in parallel. I am completely new to `openmp, this is the first time I have used it.

#include <omp.h>


int main( int argc , char **argv )
{ 
 vector <vector<string>> fileVec;
 //some code that reads in a CSV file lines into elements of fileVec

//variables constituting a line:
//my_float has been typedef to be a high precision class in real code
my_float omega;
my_float ell;

my_float init1Real;
my_float init1Imag;
my_float dinit1Real;
my_float dinit1Imag;

my_float init2Real;
my_float init2Imag;
my_float dinit2Real;
my_float dinit2Imag;

#pragma omp parallel for private(lineVec,fileVec,ell,omega,init1Real,init1Imag,dinit1Real,dinit1Imag,init2Real,init2Imag,dinit2Real,dinit2Imag)
 for (size_t i=0; i< fileVec.size(); i++) 
    { 

        lineVec=fileVec[i];


         ell=lineVec[0];
         omega=lineVec[1];

         init1Real=lineVec[2];
         init1Imag=lineVec[3];
         dinit1Real=lineVec[4];
         dinit1Imag=lineVec[5];
         init2Real=lineVec[6];
         init2Imag=lineVec[7];
         dinit2Real=lineVec[8];
         dinit2Imag=lineVec[9];


        // cout<<"OUTPUT ell=" << ell<< " omega=" << omega <<" init1Real="<<init1Real<<endl;

         //do some other calc involving these variables

    }     
   }

Solution

  • Reading from a shared fileVec is thread-safe. Only the variables of type my_float should be made private or even better - declared inside the loop:

    int main(int argc, char **argv)
    {
        vector<vector<string>> fileVec;
    
        //some code that reads in a CSV file lines into elements of fileVec
    
        #pragma omp parallel for private(lineVec)
        for (size_t i = 0; i < fileVec.size(); i++)
        {
            lineVec = fileVec[i];
    
            //my_float has been typedef to be a high precision class in real code
    
            my_float ell = lineVec[0];
            my_float omega = lineVec[1];
    
            my_float init1Real = lineVec[2];
            my_float init1Imag = lineVec[3];
            my_float dinit1Real = lineVec[4];
            my_float dinit1Imag = lineVec[5];
            my_float init2Real = lineVec[6];
            my_float init2Imag = lineVec[7];
            my_float dinit2Real = lineVec[8];
            my_float dinit2Imag = lineVec[9];
    
            cout << "OUTPUT ell=" << ell << " omega=" << omega
                 << " init1Real=" << init1Real << endl;
    
            //do some other calc involving these variables
        }
    }
    

    I don't see any races here unless my_float is not thread-safe or there is something else hidden in the //do some other calc involving these variables.

    Note that with recent OpenMP versions you can even use iterators to walk the vector, since it provides a random access iterator:

    typedef vector<vector<string>>::const_iterator iterType;
    
    #pragma omp parallel for private(lineVec)
    for (iterType it = lineVec.begin(); it != lineVec.end(); it++)
    {
        ...
    }