Как получить один и тот же вывод для распараллеливания для любого количества потоков в OpenMP для if-else, приращения? - PullRequest
0 голосов
/ 08 января 2019

Я хотел бы распараллелить следующий код без какой-либо атомарной операции или критической секции.

Ниже приведен мой код, который я уже пробовал, но результат не ожидается. Для любого количества потоков я хочу один и тот же вывод, где порядок вывода может отличаться, т. Е. 5-я строка, использующая 1 поток, может появляться в 8-й строке, когда используется 4 потока. Здесь критическим разделом является область k ++, если я не ошибаюсь. Пожалуйста, предложите, как я могу сделать это в OpenMP без использования критического / атомарного предложения.

#include <iostream>
#include <vector>
#include "omp.h"
#include "cstdlib"
using namespace std;
int main(int argc, char *argv[]){
    int t = atoi(argv[1]);
    vector<int> A{0,3,5,7};
    vector<int> B{1,2,3,0,3,0,3,0,1,2};
    int k = 0, j;
    for(int i = 0; i<A.size(); i++){
        k = A[i];
        #pragma omp parallel for schedule(static) num_threads(t)
        for(j = 0; j < A.size(); j++){
        if(j == B[k]){
            printf("i(yes):%d # B[%d] = %d, thread = %d\n",i, k, B[k], omp_get_thread_num());
            if(k < B.size() && k < A[i+1]){
                k++;
            }
        }else{
            printf("i(no):%d # j = %d, k = %d, thread =  %d\n",i, j, k, omp_get_thread_num());
        }
    }
}
return 0;
}

`
Когда я использую 1 поток, я получаю следующий вывод:

$ ./a.out 1
i(no):0 # j = 0, k = 0, thread =  0
i(yes):0 # B[0] = 1, thread = 0
i(yes):0 # B[1] = 2, thread = 0
i(yes):0 # B[2] = 3, thread = 0
i(yes):1 # B[3] = 0, thread = 0
i(no):1 # j = 1, k = 4, thread =  0
i(no):1 # j = 2, k = 4, thread =  0
i(yes):1 # B[4] = 3, thread = 0
i(yes):2 # B[5] = 0, thread = 0
i(no):2 # j = 1, k = 6, thread =  0
i(no):2 # j = 2, k = 6, thread =  0
i(yes):2 # B[6] = 3, thread = 0
i(yes):3 # B[7] = 0, thread = 0
i(no):3 # j = 1, k = 7, thread =  0
i(no):3 # j = 2, k = 7, thread =  0
i(no):3 # j = 3, k = 7, thread =  0

Но когда я запускаю 2 потока, я получаю следующий вывод, который не синхронизирован и не ожидается.

$ ./a.out 2
i(no):0 # j = 0, k = 0, thread =  0
i(yes):0 # B[0] = 1, thread = 0
i(no):0 # j = 2, k = 0, thread =  1
i(no):0 # j = 3, k = 1, thread =  1
i(no):1 # j = 2, k = 3, thread =  1
i(no):1 # j = 3, k = 3, thread =  1
i(yes):1 # B[3] = 0, thread = 0 
i(no):1 # j = 1, k = 4, thread =  0
i(no):2 # j = 2, k = 5, thread =  1
i(no):2 # j = 3, k = 5, thread =  1
i(yes):2 # B[5] = 0, thread = 0 
i(no):2 # j = 1, k = 6, thread =  0
i(yes):3 # B[7] = 0, thread = 0
i(no):3 # j = 2, k = 7, thread =  1
i(no):3 # j = 3, k = 7, thread =  1
i(no):3 # j = 1, k = 7, thread =  0

1 Ответ

0 голосов
/ 08 января 2019

Вы не можете распараллелить ваш цикл с атомами или без них. Поскольку значение k в итерации j + 1 зависит от того, что происходит в итерации j, итерации должны выполняться по порядку. (Спросите себя, как итерация с j == 2 может работать правильно, если итерация j == 1 еще не увеличилась k?)

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

...