SemaphoreSlim Sınıfı: C#'ta Çoklu Görevlere Dayalı Programlama
[en] Read in English 2023-06-10
Genel Bakış
SemaphoreSlim
sınıfı, bir veya daha fazla threadin aynı anda belirli bir kaynağı veya işlemi kullanmasını kontrol etmek için C# ‘ta kullanılan bir yapıdır. SemaphoreSlim, aynı anda kaynağa erişebilecek thread sayısını sınırlar. SemaphoreSlim
kullanımı, genellikle çok threadli uygulamalarda deadlock durumlarını önlemek ve belirli bir kaynağın aynı anda yalnızca bir veya daha fazla thread tarafından kullanılmasını sağlamak için kullanılır.
SemaphoreSlim Kullanımı
SemaphoreSlim
sınıfı, aşağıdaki gibi kullanılır:
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1);
Burada ilk parametre, aynı anda kaç threadin kaynağı kullanabileceğini belirler. İkinci parametre, semaphore’un maksimum thread sayısını belirler. Bu örnekte, her iki parametre de 1’dir, bu nedenle aynı anda yalnızca bir thread kaynağı kullanabilir.
Bir iş parçacığı, semaphore’un Wait
veya WaitAsync
metodunu çağırarak bir kaynağı talep eder:
await semaphore.WaitAsync();
Bir iş parçacığı, semaphore’un Release
metodunu çağırarak bir kaynağı serbest bırakır:
semaphore.Release();
Aşağıdaki örnekte SemaphoreSlim
kullanımını görebiliriz:
SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
async Task AccessDatabase(string name, int seconds)
{
Console.WriteLine($"{name} is requesting access to the database");
await semaphore.WaitAsync();
Console.WriteLine($"{name} has access to the database");
await Task.Delay(TimeSpan.FromSeconds(seconds));
Console.WriteLine($"{name} is done with the database");
semaphore.Release();
}
AccessDatabase("Task 1", 2);
AccessDatabase("Task 2", 2);
Bu örnekte, “Task 1” ve “Task 2” adlı iki işlem, veritabanına erişmeye çalışıyor. Ancak, semaphore sadece bir işlemin aynı anda veritabanına erişmesine izin verir. Bu nedenle, bir işlem veritabanına erişimini tamamladığında, diğer işlem veritabanına erişebilir.
Bu diyagramda, “Task 1” ve “Task 2” adlı iki işlem, bir SemaphoreSlim
‘e erişim talep ediyor. SemaphoreSlim
sadece bir işlemin aynı anda erişmesine izin verir. Bu nedenle, bir işlem erişimini tamamladığında, diğer işlem erişebilir.
Bir otoparkı düşünün. Otoparka aynı anda belirli sayıda araç park edebilir. Bu durumu, SemaphoreSlim
‘in nasıl çalıştığını anlamak için bir analoji olarak kullanabiliriz.
- Otopark = kaynak (veritabanı, dosya vb.)
- Arabalar = threadler veya taskler
- Otoparkın kapasitesi =
SemaphoreSlim
‘in ilk parametresi - Araçların park edebilmesi için bekleyen araç sayısı =
SemaphoreSlim
‘in ikinci parametresi - Araç park etmek için beklerken veya park ettikten sonra =
WaitAsync
veyaRelease
metodları
Bu benzetme, SemaphoreSlim
‘in çok threadli bir uygulamada kaynakların yönetilmesini nasıl sağladığını anlamakta yardımcı olabilir.
SemaphoreSlim
‘in Task.WhenAll
ve Task.WaitAll
ile kullanımı, birden fazla işlemi senkronize etmek için oldukça yaygındır. Bu metodlar, birden fazla Task
‘ın tamamlanmasını bekler.
Task.WhenAll ile Kullanımı
Task.WhenAll
metodu, birden fazla Task
‘ın tamamlanmasını bekler ve bir Task
döndürür. Bu Task
‘ın tamamlanması, tüm Task
‘ların tamamlanmasını gösterir. Aşağıda bir örneğini görebilirsiniz:
SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
async Task AccessDatabase(string name, int seconds)
{
Console.WriteLine($"{name} is requesting access to the database");
await semaphore.WaitAsync();
Console.WriteLine($"{name} has access to the database");
await Task.Delay(TimeSpan.FromSeconds(seconds));
Console.WriteLine($"{name} is done with the database");
semaphore.Release();
}
Task task1 = AccessDatabase("Task 1", 2);
Task task2 = AccessDatabase("Task 2", 2);
await Task.WhenAll(task1, task2);
Bu örnekte, “Task 1” ve “Task 2” adlı iki işlem, veritabanına erişmeye çalışıyor. Task.WhenAll
metodu, her iki işlemin tamamlanmasını bekler.
Task.WaitAll ile Kullanımı
Task.WaitAll
metodu, Task.WhenAll
metodu gibi çalışır, ancak Task.WaitAll
metodu, tüm Task
‘ların tamamlanmasını bloklayarak bekler. Aşağıda bir örneğini görebilirsiniz:
SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
void AccessDatabase(string name, int seconds)
{
Console.WriteLine($"{name} is requesting access to the database");
semaphore.Wait();
Console.WriteLine($"{name} has access to the database");
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine($"{name} is done with the database");
semaphore.Release();
}
Task task1 = Task.Run(() => AccessDatabase("Task 1", 2));
Task task2 = Task.Run(() => AccessDatabase("Task 2", 2));
Task.WaitAll(task1, task2);
Bu örnekte, “Task 1” ve “Task 2” adlı iki işlem, veritabanına erişmeye çalışıyor. Task.WaitAll
metodu, her iki işlemin tamamlanmasını bekler.
Bu iki metodu kullanarak, birden fazla işlemi senkronize edebilir ve bir SemaphoreSlim
ile kaynak erişimini kontrol edebilirsiniz.
Sonuç olarak, SemaphoreSlim
, çok threadli bir uygulamada aynı anda yalnızca belirli sayıda threadin bir kaynağı kullanmasını sağlar. Bu, özellikle aynı anda birden fazla threadin aynı kaynağı kullanamayacağı durumlarda önemlidir, aksi takdirde çakışmalar olabilir. Ölü kilidi önlemek ve kaynak erişimini yönetmek için SemaphoreSlim
‘i kullanabiliriz.