Interlocked Class

Stanąłem dziś przed następującym problemem. Wewnątrz klasy incrementuję, zeruję liczniki. Z zewnątrz natomiast czytam właściwość ProgressValue które oblicza wartość na podstawie liczników. Chodzi tutaj o postęp ProgressBar’a danej operacji. Jest to przykład gdzie można użyć class’y Interlocked. Oczywiście możemy też synchronizować za pomocą lock’ów, powoduje to jednak duży narzut zbędnego kodu jak i późniejszego wykonywania.
Deklaracja licznika

private int _counterA;

Operacja

_counterA++;

dzieli sie na 3 kroki (zgodnie z MSDN):

  1. Load a value from an instance variable into a register.
  2. Increment or decrement the value.
  3. Store the value in the instance variable.

Jeśli więc nasza operacja odczytu wstrzeli się w środek to dostaniemy nieaktualne dane. Sama operacja odczytu danych 32 bitowych jest już atomiczna i nie musimy korzystać z klasy Interlocked. Jest to zresztą powód dla którego brak funkcji Read(ref int32). Jest za to funkcja Read(ref long), której powinniśmy używać na maszynach 32 bitowych gdyż wtedy ta operacja nie jest atomiczna.

        public int ProgressValue
        {
            get
            {
                return _counterA; // * ... (some operations);
            }
        }

Oczywiście przykład jest przejaskrawiony i w tym przypadku nic by się nie stało gdyby korzystać ze zwykłej incrementacji (cała operacja wykonuje się w jednym wątku). Jeśli jednak operacja byłaby wielowątkowa wtedy Interlocked.Increment() zdecydowanie się przydaje.

Reklamy
Ten wpis został opublikowany w kategorii Uncategorized i oznaczony tagami , , , . Dodaj zakładkę do bezpośredniego odnośnika.