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:
lockjest 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);
}