Nano Hash - криптовалюты, майнинг, программирование

ошибка сегментации ошибка openmp

Я строю матрицу расстояний, в которой каждая строка представляет точку, а каждый столбец - это расстояние между этой точкой и всеми другими точками в данных, и мой алгоритм работает очень хорошо последовательно. Однако, когда я пытаюсь распараллелить его, я получаю ошибку ошибки сегментации. Ниже приведен мой код для параллелизма, где 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++;
  }
}
17.01.2012

  • Со всем уважением, если вы ожидаете, что мы отладим этот код, вы могли бы, по крайней мере, предоставить трассировку стека в момент сбоя. 17.01.2012
  • Пожалуйста, сделайте хотя бы отступ в своем коде, прежде чем публиковать его. 17.01.2012

Ответы:


1

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

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

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 (поправьте меня, если я ошибаюсь).

17.01.2012

2

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

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

17.01.2012
  • Обычно я предпочитаю блокировки критическому разделу, потому что мне может понадобиться добавить доступ к общей структуре данных в других точках кода, которые можно легко заставить работать с блокировками, но не так с критическими разделами, где вы не можете легко иметь разные критические секции синхронизируются друг с другом (насколько мне известно). Однако я всегда оборачивал код блокировки в класс RAII, чего не делал в своем примере для краткости. Надеюсь, вы не возражаете, если я добавлю в свой ответ пункт о datIt 17.01.2012
  • Хорошо. Я не использовал openmp широко в коде OOC. Я не уверен, что вы подразумеваете под синхронизацией друг с другом, поскольку код выполняется по одному потоку за раз. Кроме того, до и после критической секции вызывается неявный сброс, так что все в любом случае в курсе. 17.01.2012
  • Я сам не уверен на 100%, но, насколько я понимаю, я не могу защитить доступ к разделяемым конструкциям с помощью critical sections, если я обращаюсь к ним из разных частей исходного кода, поскольку пока только один поток может находиться в данной критической секции на в то же время нет запрета на одновременное нахождение тредов в разных критических секциях (думаю, если и есть, то это очень расточительно). Таким образом, критические секции защищают определенную позицию в коде, а не определенную структуру данных. Мне это не кажется хорошей идеей. 17.01.2012
  • также обратите внимание, что указания datIt как fristprivate недостаточно, так как в этом случае цикл не будет перебирать все map 17.01.2012
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..