C# ile SemaphoreSlim Kullanımı

Uzun ama çok uzun bir aradan sonra tekrardan yazı girmenin heyecanı ile bu satırlara başlıyorum 🙂 En son ki yazımın neredeyse senesi geliyordu, bu arada askerlik, sivil hayata adaptasyon, yeni iş derken bu zamana kadar sarktı. Umarım bir daha bu kadar ara vermem (her blog sahibinin tek temennisi ve sadece %10’u bu temenniyi gerçeğe dönüştürüyor 🙂 )

Konu başlığımı seçerken gerçek hayatta yeni öğrendiğim şeylerin payı büyüktür. Bende geçtiğimiz ay yeni öğrendiğim ve bir uygulamada kullanma fırsatı bulduğum SemaphoreSlim sınıfından bahsedeceğim.

Öncelikle semaphore nedir kısaca bir açıklamaya çalışayım. Daha önce “Multithread Uygulamalarda Değişken Kullanımı” makalemde birden fazla thread olduğunda yönetiminin çok zor olduğunu ve her bir thread’in aynı değişkene erişmek istemeye çalıştığında karşılaşılan sorunlardan bahsetmiştim. Semaphore ise sizin threadlerinizi yönetmenizi sağlayan bir mekanizma, bu mekanizma ile uygulamada kaç tane thread çalışacağını belirterek bütün threadlerinizi bir sıraya koyabilirsiniz. Uygulamanızda aynı anda 5 thread çalışsın diyebilirsiniz bu durumda n anında açılan 6. thread diğer 5 thread’den birinin işini bitirmesini bekler.

Bu mekanizmayı elbette kendinizde yapabilirsiniz fakat .Net Framework 4.0 ile gelen SemaphoreSlim class’ı ile bu mekanizmayı uygulamanıza entegre etmek çok kolay. Sınıfın iki tane fonksiyonu var; wait ve release bu iki fonksiyon ile programınızdaki tüm threadleri kontrol edebilirsiniz. Ufak bir kod örneği üzerinden gidecek olursak;

using System;
using System.Threading;
 
namespace SemaphoreSlim_Demo
{
    class Program
    {
        static SemaphoreSlim semaphore = new SemaphoreSlim(initialCount: 1);
 
        static void Main()
        {
            for (int i = 0; i < 5; i++)
            {
                new Thread(Process).Start(i);
            }
        }
 
        public static void Process(object threadNumber)
        {
            Console.WriteLine(string.Format("Thread Number: {0} wait", (int)threadNumber));
            semaphore.Wait();
            Console.WriteLine(string.Format("Thread Number: {0} start", (int)threadNumber));
            Thread.Sleep(1000);
            Console.WriteLine(string.Format("Thread Number: {0} finish", (int)threadNumber));
            semaphore.Release();
        }
    }
}

 

Yukarıdaki kod parçacığını inceleyecek olursak;

– Bir tane SemaphoreSlim sınıfı tanımlıyor ve başlangıç değeri olarak (initialCount: 1) parametresini geçiyoruz. Bu değer aynı anda kaç tane thread çalışabilir onun karşılığı.

– Main fonksiyonunda ufak bir döngü yaptık ve döngünün her adımında Process fonksiyonu için bir thread çalıştırdık.

– Process fonksiyonun içinde ise öncelikle semaphore.Wait() ile semaphore sınıfından bir tane boş yer istiyoruz. Boşta yer varsa işlemimize devam ediyoruz.

– İşlemimiz bittikten sonra aldığımız yeri semaphore.Release() diyerek geri bırakıyoruz.

Bu işlemin sonunda ekran çıktımız şu şekilde oluyor.

Semaphore for Initial Count: 1

Semaphore for Initial Count: 1

Çıktımıza baktığımızda aynı anda sadece tek bir thread’in  başladığını görebiliriz. Bir thread bitmeden ikinci bir thread başlamıyor. Peki initialCount değerini 3 yaptığımızda nasıl bir sonuç elde edeceğiz.

Semaphore for Initial Count: 3

Semaphore for Initial Count: 3

initialCount değerine 3 verdiğimizde aynı anda 3 tane Thread’in başladığını, bir thread bittiğinde diğer thread için yer açıldığını ve en sonunda 3 tane thread’in bittiğini görüyoruz. Son olarak initialCount değerine 5 verelim.

Semaphore for Initial Count: 5

Semaphore for Initial Count: 5

Tahmin edeceğiniz gibi bu örnek de 5 tane thread başlayıp, 5 tane thread bitecek.

Görüldüğü gibi SemaphoreSlim sınıfı ile wait, release fonksiyonları ile kolaylıkla threadlerinizi yönetebilirsiniz. Böylece farklı threadlerin çakışması, aynı değişkene erişmesi vb. hataları minumum seviyeye çekebilirsiniz.

Paylaş:
2 Responses to C# ile SemaphoreSlim Kullanımı
  1. Burak

    Merhaba,

    Bahsettiğin yöntemlerde farklı threadler aynı and aynı dosyaya erişemezler çünkü o nesneye erişim engellenmiş oluyor. SemaphoreSlim’de ise aynı anda 2 thread çalışsın dediğinde 2 thread’de aynı dosyaya erişmek isteyebilir. Bu sebeple o hatayı alıyorsun.

  2. Berat

    Merhabalar yazınız gayet güzel bence de fakat benim takldığım nokta biraz farklı.

    using (FileStream fs = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.None))

    bu satırı lock, named mutex, ReaderWriterLockSelim ya da Monitor de çalıştırırsan hiç bir sorun vermiyor. Ama semaphoreslim tanımlarsan “it is used by another proces” diyor bunun nedeniyle ilgili bir fikrin var mı?

Bir Cevap Yazın

Your email address will not be published. Please enter your name, email and a comment.