Странная проблема параллелизма с STL / OpenMP в 64-битных сборках - PullRequest
11 голосов
/ 04 апреля 2011

У меня странная проблема, когда я строю один из наших проектов в 64-битной конфигурации отладки. Похоже, что это приводит к некоторому странному поведению, похожему на то, что один итератор увеличивается несколько раз. Я сузил его до следующего кода теста:

#include <omp.h>

#define _HAS_ITERATOR_DEBUGGING 0

#include <vector>
#include <set>

int main(int argc, const char* argv[]) {    
   std::vector<int> v;
   for(int j = 0; j < 20; ++j) {
      v.push_back(j);
   }

   #pragma omp parallel for
   for(int i = 0; i < 100000; ++i) {
      std::set<int> s;
      std::vector<int>::const_iterator begin = v.begin(), end = v.end();
      s.insert(begin, end); // after this line s should contain the numbers 0-19
      if(s.size() != 20) {
         printf("fail\n");
         exit(3);
      }
   }
   return 0;
}

Тем не менее, проверка размера часто дает сбой, что подразумевает, что каким-то образом он не вставляет все содержимое вектора - и из-за большого количества попыток он выглядит так, как будто итераторы вектора увеличиваются более чем на один шаг за раз , Это довольно сложно сказать, так как этого не случится, если кто-нибудь взломает отладчик.

Очевидный вывод, который можно сделать, состоит в том, что он не является потокобезопасным, но, насколько я понимаю, так и должно быть, потому что единственная измененная переменная - это s, которая имеет локальную область видимости.

Есть несколько вещей, которые решат насущную проблему:

  • удалить параллель для
  • бросить критическую секцию вокруг insert() вызова
  • #define HAS_ITERATOR_DEBUGGING 1
  • замените одиночный вызов insert () на ручной цикл и вставьте каждый элемент по отдельности (это в основном то, что эта функция выполняет внутри, но проблема определенно исчезает, когда я делаю это сам)
  • сборка 32-битной версии того же кода
  • сборка релизной версии с тем же кодом

Это компилируется под MSVC ++ 2008 SP1, с предоставленной компилятором реализацией STL.

Может кто-нибудь пролить свет на то, что здесь происходит? Заранее спасибо за любые подсказки - я довольно озадачен:)

Редактировать: Если неясно, я не ищу "быстрое исправление", чтобы этот код работал; как отмечалось выше, я знаю довольно много из них. Я хочу понять, почему эта проблема возникает в первую очередь.

Редактировать 2: Код работает правильно при компиляции с gcc.

Ответы [ 3 ]

2 голосов
/ 04 апреля 2011

Похоже на ошибку в VS 2008 реализации OpenMP и / или STL. С VS 2010 он не воспроизводится; более того, он не воспроизводится компилятором Intel и заголовками VS 2008, что заставляет меня думать, что ошибка более вероятна в поддержке OpenMP в компиляторе VC ++.

РЕДАКТИРОВАТЬ: Код с firstprivate, который я разместил ранее, действительно не работает, даже с _SECURE_SCL = 1. Кажется, мне только что повезло.

0 голосов
/ 16 апреля 2011

Я никогда не писал никакого кода OpenMP, но я занимался многопоточным программированием, поэтому мои инстинкты могут быть или не быть правильными.

Метод insert () в наборе не является потокобезопасным, и он не работает, поскольку несколько потоков вызывают его одновременно.Вы должны заблокировать (или некоторый эквивалент OpenMP), чтобы гарантировать, что вставки выполняются последовательно.

РЕДАКТИРОВАТЬ: Попробуйте это

#include <omp.h>

#define _HAS_ITERATOR_DEBUGGING 0

#include <vector>
#include <set>


int main(int argc, const char* argv[]) {    
   std::vector<int> v;
   for(int j = 0; j < 20; ++j) {
      v.push_back(j);
   }


omp_lock_t writelock;
OMP_INIT_LOCK(&writelock);

   #pragma omp parallel for
   for(int i = 0; i < 100000; ++i) {
      std::set<int> s;
      std::vector<int>::const_iterator begin = v.begin(), end = v.end();
      OMP_SET_LOCK(&writelock);
      s.insert(begin, end); // after this line s should contain the numbers 0-19
      OMP_UNSET_LOCK(&writelock);
      if(s.size() != 20) {
         printf("fail\n");
         exit(3);
      }
   }
   return 0;
}
0 голосов
/ 16 апреля 2011

Я согласен с дархуком, я бы предложил пометить s приват

#pragma omp parallel for private(s)
...