ошибка сегментирования openmp error - PullRequest
2 голосов
/ 17 января 2012

Я строю матрицу расстояний, в которой каждая строка представляет точку, а каждый столбец - это расстояние между этой точкой и всеми другими точками в данных, и мой алгоритм последовательно работает очень хорошо. Однако, когда я пытаюсь распараллелить его, я получаю ошибку ошибки сегментации. Ниже приведен мой код для параллели, где dat - это карта, которая содержит все мои данные. Любая помощь здесь будет высоко оценена.

map< int,string >::iterator datIt;
map< int,string >::iterator datIt2;
map <int, map< int, double> > dist;
int mycont=0;
datIt=dat.begin();
int size=dat.size();
#pragma omp  parallel //construct the distance matrix
{   
  #pragma omp for   
  for(int i=0;i<size;i++)
  {
    datIt2=dat.find((*datIt).first);
    datIt2++;
    while(datIt2!=dat.end())
    {
      double ecl=0;
      int c=count((*datIt).second.begin(),(*datIt).second.end(),delm)+1;
      string line1=(*datIt).second;
      string line2=(*datIt2).second;
      for (int i=0;i<c;i++)
      {
        double num1=atof(line1.substr(0,line1.find_first_of(delm)).c_str());
        line1=line1.substr(line1.find_first_of(delm)+1).c_str();
        double num2=atof(line2.substr(0,line2.find_first_of(delm)).c_str());
        line2=line2.substr(line2.find_first_of(delm)+1).c_str();
        ecl += (num1-num2)*(num1-num2);
      }
      ecl=sqrt(ecl);
      dist[(*datIt).first][(*datIt2).first]=ecl;
      dist[(*datIt2).first][(*datIt).first]=ecl;
      datIt2++;
    }
    datIt++;
  }
}

Ответы [ 2 ]

3 голосов
/ 17 января 2012

Я не уверен, что это единственная проблема с вашим кодом, но стандартные контейнеры (такие как std::map) не являются потокобезопасными, по крайней мере, если вы пишете в них. Поэтому, если у вас есть какой-либо доступ на запись к вашему maps, например dist[(*datIt).first][(*datIt2).first]=ecl;, вам нужно обернуть любой доступ к картам в некую структуру синхронизации, используя #pragm omp critical или mutexes (omp mutex или, если вы используйте boost или C ++ 11 boost::mutex или std::mutex тоже варианты):

//before the parallel:
omp_lock_t lock;
omp_init_lock(&lock);
...

omp_set_lock(&lock);
dist[(*datIt).first][(*datIt2).first]=ecl;
dist[(*datIt2).first][(*datIt).first]=ecl;
omp_unset_lock(&lock);
...

//after the parallel:
omp_destroy_lock(&lock);

Так как вы читаете только из dat, все должно быть нормально без синхронизации (по крайней мере, в C ++ 11, C ++ 03 не имеет никаких гарантий относительно безопасности потоков (поскольку не имеет понятия о потоках). Обычно это должно быть все же можно использовать его без синхронизации, но технически это зависит от реализации.

Кроме того, поскольку вы не указали общий доступ к данным, все переменные, объявленные вне области parallel, по умолчанию являются общими. Следовательно, ваш доступ на запись к datIt и datIt2 также соответствует условиям гонки. Для datIt2 этого можно избежать, указав его как частное, или даже лучше объявив его при первом использовании:

map< int,string >::iterator datIt2=dat.find((*datIt).first);

Решение этого для datIt немного более проблематично, так как кажется, что вы хотите перебрать всю длину карты. Кажется, что самый простой способ (который не является чрезмерно дорогостоящим при использовании O(n) для каждой итерации) работает с закрытой копией datIt, которая продвигается соответствующим образом (не гарантируя 100% правильности, просто краткое описание):

#pragma omp  parallel //construct the distance matrix
{  
   map< int,string >::iterator datItLocal=datIt;
   int lastIdx = 0;
   for(int i=0;i<size;i++)
   {
      std::advance(datItLocal, i - lastIdx);
      lastIdx = i;
      //use datItLocal instead of datIt everytime you reference datIt in the parallel
     //remove ++datIt
   }
}

Таким образом, карта повторяется omp_get_num_threads() раз, но она должна работать. Если это неприемлемо для вас, посмотрите на мой ответ , чтобы найти альтернативные решения для зацикливания bidirectional iterator в openmp.

Как примечание: Может быть, я что-то пропустил, но мне кажется, что рассмотрение datIt является итератором в dat, dat.find(datIt->first) немного избыточно. На карте должен быть только один элемент с указанным ключом, и datIt указывает на него, так что это похоже на дорогой способ сказать datIt2=datIt (поправьте меня, если я ошибаюсь).

2 голосов
/ 17 января 2012

В дополнение к ответу Girzzly вы не указываете ничего личного или общего. Обычно это означает, что вы не контролируете доступ к вашей памяти. Вы должны определить datIt firstprivate и datIt2 private при входе в параллельную область, в противном случае каждая нить перезаписывает их общее значение, что приводит к ошибкам сегмента.

Вместо использования блокировок я бы использовал критическую секцию, которая более открыта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...