Я не уверен, что это единственная проблема с вашим кодом, но стандартные контейнеры (такие как 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
(поправьте меня, если я ошибаюсь).