Sobes.tech
Middle+

C#'ta çoklu iş parçacıkları ortak bir duruma eriştiğinde, iş parçacıkları ve görevlerle çalışma nasıl gerçekleşir?

sobes.tech yapay zeka

AI'dan gelen yanıt

C# dilinde çoklu akışlar tarafından paylaşılan bir durumla çalışırken senkronizasyon sorunları ve yarış durumları ortaya çıkabilir. İş akışlarının güvenliğini sağlamak için aşağıdaki mekanizmalar kullanılır:

  1. Kilitleme (Locking):

    • lock operatörü, yalnızca bir akışın korunan kaynağa erişebileceği kritik bir bölüm oluşturmak için kullanılır.
    • Genellikle private readonly object olan bir nesne kilidi kullanılır ve senkronizasyon için kullanılır.
    // lock kullanım örneği
    private readonly object _lockObject = new object();
    private int _sharedCounter = 0;
    
    public void IncrementCounter()
    {
        lock (_lockObject)
        {
            _sharedCounter++; // Kritik bölüm
        }
    }
    
  2. Atomik işlemler:

    • System.Threading.Interlocked sınıfı, Increment, Decrement, Add, Exchange gibi atomik işlemler sağlar ve bu işlemler akış güvenlidir, açık kilitlemeye gerek kalmadan yapılabilir.
    // Interlocked kullanım örneği
    private volatile int _sharedValue = 0; // volatile, değişikliklerin görünürlüğü için
    
    public void UpdateValue(int newValue)
    {
        Interlocked.Exchange(ref _sharedValue, newValue); // Atomik atama
    }
    
    public void IncrementValue()
    {
        Interlocked.Increment(ref _sharedValue); // Atomik artırma
    }
    
    • volatile, değişikliklerin akışlar arasında görünürlüğünü sağlar, ancak çok aşamalı işlemlerin atomikliğini garanti etmez. Atomik işlemler için Interlocked kullanılmalıdır.
  3. System.Threading ve System.Threading.Tasks içindeki senkronizasyon sınıfları:

    • Monitor: lock'a kıyasla daha düşük seviyeli bir kilitleme mekanizması.
    • Mutex: bir kaynağa erişimi birden fazla işlem arasında senkronize eder.
    • SemaphoreSlim: aynı anda kaynağa erişebilecek akışların sayısını sınırlar.
    • ReaderWriterLockSlim: birden fazla akışın aynı anda okumasına izin verir, ancak yalnızca bir akış yazabilir.
  4. İş parçacığı güvenli koleksiyonlar:

    • System.Collections.Concurrent isim alanı, özellikle çoklu iş parçacığı erişimi için tasarlanmış koleksiyonlar (ConcurrentBag<T>, ConcurrentDictionary<TKey, TValue>, ConcurrentQueue<T>, ConcurrentStack<T>) içerir. Bu koleksiyonların kullanımı, temel koleksiyon işlemlerinde manuel senkronizasyon ihtiyacını ortadan kaldırır.
    // ConcurrentDictionary kullanım örneği
    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. Değiştirilemez nesneler:

    • Değiştirilemez (immutable) nesnelerin oluşturulması, oluşturulduktan sonra durumlarının değiştirilemeyeceği anlamına gelir. Paylaşılan durumu temsil eden değiştirilemez bir nesne varsa, birden fazla akış onu güvenle okuyabilir ve senkronize olmadan kullanabilir. Durum güncellemesi, yeni bir nesne örneği oluşturmaya indirgenir.

TPL (Task Parallel Library) içindeki görevlerle (Task) çalışırken, paylaşılan duruma erişimde senkronizasyonu da göz önünde bulundurmak gerekir. TPL, paralel işlemlerin oluşturulmasını ve yönetimini kolaylaştırır, ancak paylaşılan verilerle çalışırken akış güvenliğini sağlama sorumluluğunu ortadan kaldırmaz.

Uygun senkronizasyon mekanizmasının seçimi, belirli göreve ve paylaşılan duruma erişim özelliklerine bağlıdır.