Sobes.tech
Middle+

Kuidas toimub töö C#-s niitide ja ülesannetega, kui mitu niiti pääsevad ligi ühisele olekule?

sobes.tech AI

Vastus AI-lt

Strādājot ar kopējo stāvokli vairākās pavedienos C# ir radušās sinhronizācijas problēmas un iespējamās sacensību stāvokļa situācijas. Lai nodrošinātu pavedienu drošību, tiek izmantoti šādi mehānismi:

  1. Bloķēšana (Locking):

    • Tiek izmantots lock operators, lai izveidotu kritisko sekciju, kas garantē, ka tikai viens pavedienu vienlaicīgi var piekļūt aizsargātajam resursam.
    • Prasa objekta aizslēgšanas objektu (parasti private readonly object), kas tiek izmantots sinhronizācijai.
    // Piemērs ar lock
    private readonly object _lockObject = new object();
    private int _sharedCounter = 0;
    
    public void IncrementCounter()
    {
        lock (_lockObject)
        {
            _sharedCounter++; // Kritiskā sekcija
        }
    }
    
  2. Atomaras operācijas:

    • System.Threading.Interlocked klase nodrošina atomaras operācijas (piemēram, Increment, Decrement, Add, Exchange), kas ir pavedienu drošas un neprasa skaidru bloķēšanu vienai operācijai.
    // Piemērs ar Interlocked
    private volatile int _sharedValue = 0; // volatile, lai nodrošinātu redzamību
    
    public void UpdateValue(int newValue)
    {
        Interlocked.Exchange(ref _sharedValue, newValue); // Atomāra piešķiršana
    }
    
    public void IncrementValue()
    {
         Interlocked.Increment(ref _sharedValue); // Atomāra palielināšana
    }
    
    • Nors volatile nodrošina izmaiņu redzamību starp pavedieniem, tas nesniedz atomaritātes garantiju daudzposmu operācijām. Lai veiktu atomaras operācijas, izmantojiet Interlocked.
  3. Sinhronizācijas klases no System.Threading un System.Threading.Tasks:

    • Monitor: zemākā līmeņa bloķēšanas mehānisms salīdzinājumā ar lock.
    • Mutex: ļauj sinhronizēt piekļuvi resursam starp vairākām procesiem.
    • SemaphoreSlim: ierobežo vienlaicīgi pieejamo pavedienu skaitu.
    • ReaderWriterLockSlim: ļauj daudziem pavedieniem vienlaicīgi lasīt resursu, bet tikai vienam rakstīt.
  4. Pavedienu drošas kolekcijas:

    • System.Collections.Concurrent telpa satur kolekcijas (ConcurrentBag<T>, ConcurrentDictionary<TKey, TValue>, ConcurrentQueue<T>, ConcurrentStack<T>), kas ir izstrādātas īpaši daudzpavedienu piekļuvei. Šo kolekciju izmantošana samazina nepieciešamību pēc manuālas sinhronizācijas ar kolekcijas pamatoperācijām.
    // Piemērs ar 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);
    }
    
  5. Nemaināmi objekti (Immutable objects):

    • Nemaināmu objektu izveide nozīmē, ka pēc to izveides to stāvokli nevar mainīt. Ja kopējais stāvoklis ir nemaināms objekts, vairāki pavedieni var droši to lasīt bez sinhronizācijas. Būsena tiek atjaunināta, izveidojot jaunu objekta eksemplāru.

Strādājot ar uzdevumiem (Task) TPL (Task Parallel Library), arī ir jāņem vērā sinhronizācija piekļuvei kopējai stāvokļa informācijai. TPL atvieglo paralēlo operāciju izveidi un pārvaldību, bet nesamazina atbildību par datu drošību.

Izvēle piemērotā sinhronizācijas mehānisma ir atkarīga no konkrētās uzdevuma un piekļuves kopējai stāvokļa īpašībām.