Kako se u C# radi sa nitima i zadacima kada više niti pristupaju zajedničkom stanju?
sobes.tech АИ
Одговор од АИ
Kada radite sa zajedničkim stanjem u C# sa više niti, javljaju se problemi sa sinhronizacijom i moguće trkačke uslove. Sledeći mehanizmi se koriste:
-
Zaključavanje (Locking):
- Koristi se operator
lockza kreiranje kritične sekcije, koja garantuje da samo jedna nit može pristupiti zaštićenom resursu odjednom. - Potreban je objekat-zaštitnik (obično
private readonly object) koji se koristi za sinhronizaciju.
// Primer korišćenja lock private readonly object _lockObject = new object(); private int _sharedCounter = 0; public void IncrementCounter() { lock (_lockObject) { _sharedCounter++; // Kritična sekcija } } - Koristi se operator
-
Atomarne operacije:
- Klasa
System.Threading.Interlockedpruža atomarne operacije (npr.,Increment,Decrement,Add,Exchange), koje su sigurnе za niti i ne zahtevaju eksplicitno zaključavanje.
// Primer korišćenja Interlocked private volatile int _sharedValue = 0; // volatile za vidljivost promena public void UpdateValue(int newValue) { Interlocked.Exchange(ref _sharedValue, newValue); // Atomik dodeljivanje } public void IncrementValue() { Interlocked.Increment(ref _sharedValue); // Atomik povećanje }- Iako
volatileobezbeđuje vidljivost promena između niti, ne garantuje atomarnost višestepenih operacija. Za atomarne operacije, koristi seInterlocked.
- Klasa
-
Klase za sinhronizaciju iz
System.ThreadingiSystem.Threading.Tasks:Monitor: nižeg nivoa mehanizam zaključavanja u poređenju salock.Mutex: omogućava sinhronizaciju pristupa resursu između više procesa.SemaphoreSlim: ograničava broj niti koje istovremeno mogu pristupiti resursu.ReaderWriterLockSlim: omogućava više niti da čitaju resurs istovremeno, ali samo jedna da piše.
-
Sigurne za niti kolekcije:
- Prostor imena
System.Collections.Concurrentsadrži kolekcije (ConcurrentBag<T>,ConcurrentDictionary<TKey, TValue>,ConcurrentQueue<T>,ConcurrentStack<T>), dizajnirane posebno za višestruki pristup. Korišćenje ovih kolekcija uklanja potrebu za ručnom sinhronizacijom pri osnovnim operacijama sa kolekcijom.
// Primer korišćenja 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); } - Prostor imena
-
Nemijenjivi objekti (Immutable objects):
- Kreiranje nemijenjivih objekata znači da se njihovo stanje ne može promijeniti nakon kreiranja. Ako je zajedničko stanje predstavljeno nemijenjivim objektom, više niti može sigurno da ga čita bez potrebe za sinhronizacijom. Ažuriranje stanja svodi se na kreiranje novog primjerka objekta.
Prilikom rada sa zadacima (Task) u TPL (Task Parallel Library) takođe je potrebno razmotriti sinhronizaciju pri pristupu zajedničkom stanju. TPL olakšava kreiranje i upravljanje paralelnim operacijama, ali ne uklanja odgovornost za obezbeđenje sigurnosti pri radu sa zajedničkim podacima.
Izbor odgovarajućeg mehanizma za sinhronizaciju zavisi od konkretne zadatka i karakteristika pristupa zajedničkom stanju.