Race conditions
Časově Závislé Chyby a Mechanizmy pro Synchronizaci Vláken v C#
Časově Závislé Chyby (Race Conditions)
Časově závislé chyby, nebo race conditions, nastávají, když dvě nebo více vláken přistupuje k sdíleným datům současně, přičemž alespoň jedno z vláken tato data mění. To může vést k nekonzistentním nebo nečekaným výsledkům, protože pořadí operací není předem určeno.
Příklad:
int pocitadlo = 0;
void ZvysitPocitadlo()
{
for (int i = 0; i < 1000; i++)
{
pocitadlo++;
}
}
Thread vlakno1 = new Thread(ZvysitPocitadlo);
Thread vlakno2 = new Thread(ZvysitPocitadlo);
vlakno1.Start();
vlakno2.Start();
vlakno1.Join();
vlakno2.Join();
Console.WriteLine(pocitadlo); // Výstup může být nekonzistentní kvůli race condition
V tomto případě dvě vlákna současně zvyšují hodnotu proměnné pocitadlo, což může vést k nekonzistentním výsledkům kvůli race condition.
Mechanizmy pro Synchronizaci Vláken
-
lockBlok:lockblokuje přístup ke sdílenému zdroji, aby zajistil, že pouze jedno vlákno může provádět kritickou sekci kódu najednou.
Příklad:
private static readonly object zamek = new object(); void ZvysitPocitadloBezpecne() { lock(zamek) { for (int i = 0; i < 1000; i++) { pocitadlo++; } } }lockzajišťuje, že jakmile jedno vlákno vstoupí do kritické sekce, ostatní vlákna musí počkat, dokud není tato sekce dokončena.
-
MonitoraMutex:Monitorje podobnýlock, ale nabízí více funkcí, jako je explicitní čekání a signalizace.Mutex(Mutual Exclusion) se používá pro synchronizaci vláken napříč různými procesy.
Příklad s
Monitor:Monitor.Enter(zamek); try { // Kritická sekce } finally { Monitor.Exit(zamek); }
Priklad s Mutex
using System;
using System.Threading;
class Program
{
// Vytvoření globálního mutexu
static Mutex mutex = new Mutex();
static void Main()
{
Thread vlakno1 = new Thread(Pracuj);
Thread vlakno2 = new Thread(Pracuj);
vlakno1.Start();
vlakno2.Start();
vlakno1.Join();
vlakno2.Join();
Console.WriteLine("Obě vlákna dokončena.");
}
static void Pracuj()
{
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} čeká na mutex...");
mutex.WaitOne(); // Čeká na získání mutexu
try
{
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} získal mutex, pracuje...");
Thread.Sleep(2000); // Simulace práce
}
finally
{
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} uvolňuje mutex.");
mutex.ReleaseMutex(); // Uvolnění mutexu
}
}
}
-
AutoResetEventaManualResetEvent:- Tyto třídy umožňují vláknům čekat, dokud nejsou signalizovány k pokračování.
Příklad:
AutoResetEvent autoEvent = new AutoResetEvent(false); void Pracuj() { Console.WriteLine("Čekám na signál..."); autoEvent.WaitOne(); // Čeká na signál Console.WriteLine("Pracuji po signálu"); } // Spuštění vlákna Thread vlakno = new Thread(Pracuj); vlakno.Start(); // Signalizace vlákna k pokračování autoEvent.Set();
Shrnutí
- Časově závislé chyby vznikají, když více vláken přistupuje ke sdíleným datům bez správné synchronizace.
- Mechanizmy pro synchronizaci jako
lock,Monitor,Mutex,AutoResetEvent, aManualResetEventjsou klíčové pro zajištění správného a bezpečného přístupu ke sdíleným prostředkům mezi vlákny.