Middle+
Kaip vyksta darbai su srautais ir užduotimis C# kalboje, kai keli srautai kreipiasi į bendrą būseną?
sobes.tech AI
Atsakymas iš AI
Dirbant su bendru būsena keliuose srautuose C# kyla sinchronizacijos problemų ir galimų lenktynių sąlygų. Norint užtikrinti srautų saugumą, naudojami šie mechanizmai:
-
Užraktas (Locking):
- Naudojamas
lockoperatorius kritinei sekcijai sukurti, garantuojant, kad tik vienas srautas gali vienu metu pasiekti saugomą išteklių. - Reikalauja objektinio užrakto objekto (paprastai
private readonly object), kuris naudojamas sinchronizacijai.
// Pavyzdys naudojant lock private readonly object _lockObject = new object(); private int _sharedCounter = 0; public void IncrementCounter() { lock (_lockObject) { _sharedCounter++; // Kritinė sekcija } } - Naudojamas
-
Atomarinės operacijos:
System.Threading.Interlockedklasė teikia atomines operacijas (pvz.,Increment,Decrement,Add,Exchange), kurios yra srautui saugios ir nereikalauja aiškios užrakto taikymo vienai operacijai.
// Pavyzdys naudojant Interlocked private volatile int _sharedValue = 0; // volatile matomumui public void UpdateValue(int newValue) { Interlocked.Exchange(ref _sharedValue, newValue); // Atomarinis priskyrimas } public void IncrementValue() { Interlocked.Increment(ref _sharedValue); // Atomarinis didinimas }- Nors
volatileužtikrina pokyčių matomumą tarp srautų, jis nesuteikia atomariškumo daugiasluoksnių operacijų. Atomariškoms operacijoms naudokiteInterlocked.
-
Sinchronizacijos klasės iš
System.ThreadingirSystem.Threading.Tasks:Monitor: žemesnio lygio užrakto mechanizmas, palyginti sulock.Mutex: leidžia sinchronizuoti prieigą prie išteklių tarp kelių procesų.SemaphoreSlim: riboja vienu metu prieinamų srautų skaičių.ReaderWriterLockSlim: leidžia daugeliui srautų vienu metu skaityti išteklius, bet tik vienam rašyti.
-
Srautui saugios kolekcijos:
System.Collections.Concurrenterdvė apima kolekcijas (ConcurrentBag<T>,ConcurrentDictionary<TKey, TValue>,ConcurrentQueue<T>,ConcurrentStack<T>), sukurtas specialiai daugiagretėms prieigoms. Šių kolekcijų naudojimas sumažina poreikį rankiniu būdu sinchronizuoti bazines operacijas.
// Pavyzdys naudojant ConcurrentDictionary private ConcurrentDictionary<string, int> _sharedData = new ConcurrentDictionary<string, int>(); public void AddOrUpdateData(string key, int value) { _sharedData.AddOrUpdate(key, value, (k, oldValue) => oldValue + value); } -
Nekeičiami objektai (Immutable objects):
- Sukurti nekeičiami objektai reiškia, kad jų būsena po sukūrimo negali būti pakeista. Jei bendroji būsena yra nekeičiama objekto reprezentacija, keli srautai gali saugiai ją skaityti be sinchronizacijos. Būsena atnaujinama kuriant naują objekto egzempliorių.
Dirbant su užduotimis (Task) TPL (Task Parallel Library), taip pat būtina atsižvelgti į sinchronizaciją prieigai prie bendros būsenos. TPL palengvina paralelinių operacijų kūrimą ir valdymą, bet nesumažina atsakomybės už duomenų saugumą.
Pasirinkimas tinkamo sinchronizacijos mechanizmo priklauso nuo konkrečios užduoties ir prieigos prie bendros būsenos ypatybių.