Paralel programlamada bir işlemi "aniden öldürmek" (thread abort) çok tehlikelidir; veritabanı bağlantıları açık kalabilir, dosya kilitleri bozulabilir. .NET dünyasında biz bunu Cooperative Cancellation (İşbirlikçi İptal) dediğimiz, CancellationToken mekanizması ile yönetiriz.
1. CancellationTokenSource ve Token İlişkisi
İptal işleminin iki tarafı vardır:
CancellationTokenSource (CTS): Tetiği çeken eldir. "İptal et" emrini bu nesne verir.
CancellationToken: Bu emri dinleyen kulaktır. Metodlara parametre olarak geçilir.
2. Parallel.ForEach İçinde İptal Yönetimi
Paralel bir döngüde yüzlerce iş parçacığı aynı anda çalışırken, birinin iptal sinyali alması hepsinin durması gerektiği anlamına gelir. ParallelOptions kullanarak bu sinyali döngüye iletebiliriz.
public async Task ProcessDataWithCancellationAsync(List<string> items)
{
using var cts = new CancellationTokenSource();
// 5 saniye sonra otomatik iptal et (Timeout senaryosu)
cts.CancelAfter(TimeSpan.FromSeconds(5));
var options = new ParallelOptions
{
CancellationToken = cts.Token,
MaxDegreeOfParallelism = Environment.ProcessorCount
};
try
{
await Parallel.ForEachAsync(items, options, async (item, token) =>
{
// Senior Notu: Her adımda token'ı kontrol etmek veya
// destekleyen asenkron metodlara token'ı geçmek zorundasınız.
await PerformWorkAsync(item, token);
// Eğer ağır bir CPU işlemi varsa manuel kontrol:
token.ThrowIfCancellationRequested();
});
}
catch (OperationCanceledException)
{
Console.WriteLine("İşlem kullanıcı veya timeout tarafından iptal edildi.");
}
}3. İşbirlikçi İptal (Cooperative) Neden Önemli?
İptal sinyali geldiğinde kodunuz anında durmaz. Sizin kodun içinde belli aralıklarla "İptal edildim mi?" diye sormanız gerekir:
token.ThrowIfCancellationRequested(): Eğer iptal sinyali varsa bir exception fırlatır ve işlemi güvenli bir şekilde keser.token.IsCancellationRequested: Eğer exception fırlatmadan "temizlik" (dosya kapatma, bağlantı kesme) yapıp çıkmak istiyorsanız bu property'yi kullanırsınız.
4. Linked CancellationToken (Gelişmiş Senaryo)
Bazen bir işlemi birden fazla durum iptal edebilir. Örneğin hem kullanıcının iptal butonu hem de sistemin global timeout süresi. Senior bir geliştirici bunları birbirine bağlar:
var userCts = new CancellationTokenSource();
var timeoutCts = new CancellationTokenSource(10000); // 10 sn
// İki sinyali birleştiriyoruz
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(userCts.Token, timeoutCts.Token);
// İkisinden biri iptal edilirse linkedCts.Token iptal olur.
await Task.Run(() => DoWork(linkedCts.Token), linkedCts.Token);