OpenMP — вызов внешних функций в параллельном цикле for

#c #multithreading #parallel-processing #openmp

#c #многопоточность #параллельная обработка #openmp

Вопрос:

У меня очень мало опыта использования OpenMP. Я пытаюсь параллельно запустить цикл for, который вызывает другую внешнюю функцию. Я компилирую программу с помощью MinGW, поэтому, к сожалению, я не получаю никаких ошибок, указывающих на то, что я делаю неправильно, программа просто не запускается, когда я пытаюсь добавить parallel for вне моего цикла. findCombinations() — довольно большая функция, которая сама вызывает другую функцию. Мне интересно, возможно ли использовать параллельный цикл for в этом сценарии? и если да, есть ли что-нибудь, что я делаю явно неправильно?

 #pragma omp parallel for
for(int j = 0; j < n[i].count; j  ) { 
    int length = 0;
    while(n[i].neighbourhoods[j][length].index != -1) length  ;
    bool used[length];
    memset(used, false, sizeof(used));
    findCombinations(amp;b, n[i].neighbourhoods[j], length, 0, 0, used, n[i].col);
    free(n[i].neighbourhoods[j]);
}
  

Вот findCombinations()

 int findCombinations(struct blocks *b, struct element neighbourhood[], int neighbourhoodSize, int start, int currLen, bool used[], int col) {    
    if (currLen == blocksize) {
        b->blocks[b->count].elements = malloc((blocksize 1) * sizeof(struct element)); 
        b->blocks[b->count].col = col;
        int blockCount = 0;
        for (int i = 0; i < neighbourhoodSize; i  ) {
            if (used[i] == true) {
                b->blocks[b->count].elements[blockCount  ] = neighbourhood[i];
            }
        }
        b->blocks[b->count].elements[blocksize] = neighbourhood[neighbourhoodSize]; //ensures the last item is -1
        b->blocks[b->count].signature = getSignature(b->blocks[b->count].elements);
        return 1;
    }
    if (start == neighbourhoodSize) {
        return 0;
    }
    int new = 0;

    used[start] = true;
    b->count  = findCombinations(b, neighbourhood, neighbourhoodSize, start   1, currLen   1, used, col);

    used[start] = false;
    b->count  = findCombinations(b, neighbourhood, neighbourhoodSize, start   1, currLen, used, col);

    return new;
}
  

Я думаю, проблема может заключаться в том, что findCombinations() изменяет указатель, который я отправляю на него, *b , что может вызвать состояние гонки. Моя проблема в том, что я не уверен, как ее обойти.

Комментарии:

1. Пожалуйста, предоставьте полный пример, чтобы мы могли лучше помочь вам. Первая мысль — убедитесь, что вы включили поддержку OpenMP в своем компиляторе. Например, если вы используете GCC в Linux, вам нужно включить -fopenmp в строку компиляции.

2. Извините — добавлена функция, вызываемая им сейчас. Я использую Windows, и я установил MinGW для компиляции с помощью gcc, просто компилирую через командную строку с помощью -fopenmp

3. Конечно, у вас проблема со всеми вашими потоками, работающими с одним и тем же указателем b . Становится еще хуже, когда понимаешь, что findCombinations() это рекурсивная функция. Вероятно, вы сможете исправить это, используя некоторые critical разделы здесь и там, но я сомневаюсь, что окончательное ускорение будет стоить того. Если вам нужна производительность, вам, вероятно, лучше серьезно пересмотреть свой алгоритм.

Ответ №1:

Использование функций из других библиотек вполне допустимо в параллельных областях OpenMP при условии, что эти библиотеки предоставляют потокобезопасные процедуры, в противном случае вы можете подвергнуться гонкам данных, которые вы не можете контролировать, и, следовательно, вы можете выполнять только один рутинный вызов за раз.

Если вы не уверены, является ли ваша программа потокобезопасной, вы можете попробовать использовать некоторые инструменты, такие как helgrind от Valgrind или средство очистки потоков GCC / LLVM.