Ostatnio uczę się programowania równoległego w C przy pomocy OpenMP.
Zacząłem od prostej kwestii inkrementowania zmiennej przechowywanej w pamięci współdzielonej.
Na początku użyłem dyrektywy reduction, zadziałało zgodnie z oczekiwaniami.
Następnie zastępiłem ją critical, tworząc sekcję krytyczną - również działało.
Po tym wszystkim zrobiłem się ciekawy i chciałem zobaczyć co się stanie, gdy użyję obydwu dyrektyw jednocześnie. Zdaje sobie sprawę, że nie ma żadnego sensu pisać tego w ten sposób - po prostu byłem ciekawy.
Oto kod:
#include <stdio.h>
#include <stdlib.h>
#include "omp.h"
#define ITER 50000
int main( void )
{
int x, y;
#pragma omp parallel reduction(+:x,y)
{
#pragma omp for
for (int i = 0; i < ITER; i++ )
{
x++;
#pragma omp critical
y++;
}
}
printf("non critical = %d\ncritical = %d\n", x, y);
return 0;
}
przykładowy output:
non critical = 50000
critical = 4246432
Z tego co rozumiem dyrektywa reduction tworzy ze zmiennych x, y zmienne prywatne, widoczne tylko dla wątku, które po zakończeniu bloku równoległego sumuje i wrzuca do zmiennych x,y we współdzielonej pamięci.
Tak więc wartość x mnie nie dziwi.
Za to co się dzieje z y nie mam zielonego pojęcia. Przed wykonaniem byłem pewny, że obie wartości będą równe.
"Lokalne" y jest widoczne tylko dla jednego wątku więc założenie na nie sekcji krytycznej nie powinno zmienić zachowania programu - tak czy inaczej tylko jeden wątek będzie operował na swojej zmiennej lokalnej. Tymczasem mam wrażenie, że dyrektywa critical "upubliczniła" lokalną zmienną wywołując wyścig.
Zarówno o C jak i o programowaniu równoległym dopiero się uczę więc jest spora szansa, że pytanie jest trywialne.
Byłbym wdzięczny za wyjaśnienie powyższego zachowania.