2012-01-17 2 views
2

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

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

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

+0

Пожалуйста, по крайней мере открепите свой код перед его отправкой. –

ответ

3

Я не уверен, если это единственная проблема с вашим кодом, но стандартные контейнеры (такие как 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 это должно быть хорошо без Syncronization (в C++ 11, по крайней мере, C++ 03 не имеет никаких гарантий относительно threadsafety вообще (так как она не имеет концепция потоков). Обычно должно быть хорошо использовать его без синхронизации, но технически это зависит от его реализации.

Кроме того, поскольку вы не указали передачу данных, все переменные, объявленные за пределами области 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() раз, но она должна работать. Если это неприемлемые накладные расходы для вас, посмотрите на this answer of mine для альтернативных решений для петли на bidirectional iterator в openmp.

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

2

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

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

+0

Я предпочитаю блокировки для критической секции, потому что я мог бы добавить доступ к общей структуре данных в других точках кода, которые могут легко работать с замками, но не так с критическими разделами, где вам нелегко разные критические разделы синхронизируются друг с другом (насколько мне известно). Тем не менее, я бы оборачивал код блокировки в классе RAII, чего я не делал в своем примере для краткости. Надеюсь, вы не возражаете, если я добавлю пункт о 'datIt' к моему ответу. – Grizzly

+0

Все в порядке. Я не использовал openmp в коде OOC. Я не уверен, что вы подразумеваете под синхронизацией друг с другом, поскольку код выполняется по одному потоку за раз. Кроме того, до и после критической секции подразумевается скрытый флеш, так что все в любом случае актуальны. – Bort

+0

Я не уверен на 100% сам, но так, как я его вижу, я не могу защитить доступ к общим конструкциям с помощью «критических разделов», если я получаю доступ к ним из разных частей исходного кода, поскольку, хотя только один поток может находиться в одновременно с критическим разделом, запрет на то, что потоки не встречаются в разных критических срезах одновременно (я думаю, если это кажется действительно расточительным). Поэтому критические разделы защищают определенную позицию в коде, а не определенную структуру данных. На самом деле это не очень хорошая идея для меня. – Grizzly

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