Как сделать этот поток кода безопасным с openMP?

Схематический код, показанный ниже, работает нормально, если я удаляю #pragma omp parallel for, но с этим на месте код компилируется, но затем при выполнении бинарного файла я получаю такие ошибки, как *** glibc detected *** ./testBin: double free or corruption (!prev): 0x0c43d8d8 *** а также core dumped, Я предполагаю, что причина в том, что несколько потоков пытаются записать в переменные omega, ell, .... или же lineVec, Как это исправить? Есть ли способ сказать, что переменные являются общими? или есть просто вообще другой способ сделать этот цикл параллельно. Я совершенно новичок в `openmp, я впервые его использую.

#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

}
}

1

Решение

Чтение из общего fileVec является потокобезопасный. Только переменные типа my_float должно быть сделано private или даже лучше — объявлено внутри цикла:

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
}
}

Я не вижу здесь никаких гонок, если только my_float не является потокобезопасным или что-то еще скрыто в //do some other calc involving these variables,

Обратите внимание, что в последних версиях OpenMP вы можете даже использовать итераторы для обхода вектора, поскольку он предоставляет итератор с произвольным доступом:

typedef vector<vector<string>>::const_iterator iterType;

#pragma omp parallel for private(lineVec)
for (iterType it = lineVec.begin(); it != lineVec.end(); it++)
{
...
}
5

Другие решения

Как вы и написали, openmp создаст несколько потоков и поделит общее количество итераций цикла for между всеми потоками. При этом он попытается выполнить параллельное чтение вектора, общего для разных потоков. Вы можете изменить атрибуты обмена данными, (см. OpenMP Wiki о предложениях атрибутов совместного использования данных, и в этом Microsoft DOC у вас есть хороший пример, как это сделать. Например, чтобы объявить lineVec и fileVec как «личное», используйте:

#pragma omp parallel private(lineVec, fileVec)

Кроме того, cout не является потокобезопасным, и вызовы cout из нескольких потоков также должны быть сериализованы.

1

По вопросам рекламы [email protected]