2015-11-27 2 views
0

У меня есть программа на C++, где я пытаюсь использовать openmp в цикле for. Цикл for работает с shared_ptr в моем собственном классе, который, в свою очередь, вызывает другую dll. Я получаю ошибки:C++ openmp shared_ptr datarace

Таблица 7. Текущий указатель и in_use_count непоследовательны.

код выглядит примерно так ..

int n = 1000; 
    std::vector<double> result(n),indata(n); 

    // populate indata 

    std::shared_ptr<MyNS::MyClass> sp_mycl = std::make_shared <MyNS::MyClass>(); 
    sp_mycl->var1 = 2; 
    // populate sp_mycl->v_var4 
    #pragma omp parallel for firstprivate(sp_mycl) 
    for (auto ii = 0; ii<n;ii++) 
    { 
     sp_mycl->var2 = indata[ii]; 
     sp_mycl->calc(); 
     result[ii] = sp_mycl->var3; 
    } 

и MyClass.h похож на этот

namespace MyNS 
{ 
    extern "C" { double * fortran_dll_calc(int *num, double arrinput[],double arroutput[])} // subroutine in fortran dll 
    class MyClass 
    { 
     double var1, var2, var3; 
     std::vector<double> v_var4; 
     void calc(); 
    } 
} 

и MyClass.cpp

using namespace MyNS; 
void MyClass::calc() 
{ 
    int len = v_var4.size(); 
    double *test = new double[len]; 
    for (auto is = 0; is<len;is++) 
     test[is] = v_var4[is]; 
    double fortran_result[10]; // output from fortran dll 
    fortran_dll_calc(len,test,fortran_result); 
    for (int ir = 0;ir < 10;ir++) 
     var3 += fortran_result[ir]; 
} 

я использую МСВС с компилятором Intel parallel studio C++/fortran 2016.

Я хочу, чтобы sp_mycl->var1 имел одинаковое значение для всех потоков, поэтому firstprivate для sp_mycl.

Путь к openmp для петли, кажется, где-то идет не так, и когда отладка иногда кажется остановленной внутри MyClass::calc(), а иногда уже на sp_mycl->var2= indata[ii]. Это я обнаружил, используя некоторые выходы cout.

Является ли firstprivate, работающим с shared_ptr собственными определенными объектами? Я новичок, поэтому может быть много ошибок и ошибок, любой комментарий на что-либо в коде оценивается.

ответ

1

OpenMP собирается инициализировать собственную версию sp_mycl для каждой нити следующим образом:

auto priv_sp_mycl = sp_mycl; 

Это делается параллельно и вызывает конструктор копирования, который необходимо, наконец, необходимо обновить подсчет ссылок для shared_ptr. Однако реализация shared_ptr в STL не является потокобезопасной, поэтому происходит то, что происходит.

Однако я не уверен, что это то, что вы хотите. Почему вы хотите, чтобы каждый поток указывал на один и тот же объект? Разве это не привело бы к дополнительным условиям гонки в вашей программе? Также каждый поток записывает результат в result[n] ... Вы имели в виду result[ii]?

Во всяком случае, я думаю, что это то, что вы хотите:

MyNS::MyClass sp_mycl; 
sp_mycl.var1 = 2; 
// populate sp_mycl->v_var4 
#pragma omp parallel for firstprivate(sp_mycl) 
for (auto ii = 0; ii<n;ii++) 
{ 
    sp_mycl.var2 = indata[ii]; 
    sp_mycl.calc(); 
    result[ii] = sp_mycl.var3; 
} 
+0

Большое спасибо @ simple01. Единственное, что мне интересно, это если опасно ставить много предметов в стек? –

+0

Каждый поток имеет отдельный стек ... и вы помещаете только один объект MyClass, каждый из которых равен '3 * sizeof (double) + sizeof (std :: vector)', который составляет около 200 байт (помните std :: вектор выполняет выделение памяти в куче, а не в стеке). Я думаю, что использование стека не является проблемой. – simpel01

Смежные вопросы