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.