Sobes.tech
Middle+

Jak obsługiwać pracę z wątkami (threads) i zadaniami (tasks), gdy kilka z nich odwołuje się do wspólnego stanu?

sobes.tech AI

Odpowiedź od AI

Aby bezpiecznie odwołać się do stanu współdzielonego w środowisku wielowątkowym, używa się mechanizmów synchronizacji.

Główne podejścia:

  • Blokady: lock jest najpowszechniejszym mechanizmem. Zapewnia wyłączny dostęp do bloku kodu lub obiektu dla jednego wątku na raz. Mutex (wzajemne wykluczenie) jest również używany, ale często w komunikacji międzyprocesowej.
  • Semantyki: Ograniczają liczbę wątków, które mogą jednocześnie uzyskać dostęp do zasobu.
  • Monitor: Reprezentuje bardziej zaawansowaną wersję lock, pozwalającą wątkom oczekiwać powiadomień od innych wątków.
  • ReadWriteLock: Pozwala wielu wątkom czytać dane jednocześnie, ale tylko jednemu na pisanie.
  • Operacje atomowe: Dla prostych operacji (inkrementacja, dekrementacja, porównanie-zamiana) można używać statycznych metod klasy Interlocked.

Przy pracy z zadaniami (Tasks), szczególnie z użyciem async/await, ważne jest, aby pamiętać, że zadania nie są powiązane z konkretnym wątkiem. Konteksty synchronizacji (SynchronizationContext) pomagają wrócić do odpowiedniego kontekstu (np. wątku UI) po zakończeniu operacji asynchronicznej.

Przykład użycia lock:

// Obiekt do blokowania
private readonly object _lockObject = new object();
private int _sharedCounter = 0;

public void IncrementCounter()
{
    // Blokuje dostęp do wspólnego licznika
    lock (_lockObject)
    {
        _sharedCounter++;
    }
}

Przykład użycia Interlocked:

private int _sharedAtomicCounter = 0;

public void IncrementAtomicCounter()
{
    // Atomowe zwiększenie
    Interlocked.Increment(ref _sharedAtomicCounter);
}