Özel durum işleme (Görev Paralel Kitaplığı)

Bir görevin içinde çalışan kullanıcı kodu tarafından atılan işlenmeyen özel durumlar, bu konunun ilerleyen bölümlerinde açıklanan bazı senaryolar dışında, çağıran iş parçacığına geri yayılır. Statik veya örnek Task.Wait yöntemlerinden birini kullandığınızda ve çağrıyı bir try/catch deyimi içine alarak bunları işleyerek özel durumlar yayılır. Görev, ekli alt görevlerin üst öğesiyse veya birden çok görev bekliyorsanız, birden çok özel durum oluşturulabilir.

Tüm özel durumları çağrı yapan iş parçacığına geri yaymak için, Görev altyapısı onları bir AggregateException örneği içine sarar. Özel AggregateException durum, atılan tüm özgün özel durumları incelemek ve her birini ayrı ayrı işlemek (veya işlememek) için numaralandırılabilir bir InnerExceptions özelliğe sahiptir. Ayrıca yöntemini kullanarak AggregateException.Handle özgün özel durumları işleyebilirsiniz.

Yalnızca bir özel durum oluşturulduğunda bile, aşağıdaki örnekte gösterildiği gibi bir AggregateException özel durum içinde sarmalanır.


public static partial class Program
{
    public static void HandleThree()
    {
        var task = Task.Run(
            () => throw new CustomException("This exception is expected!"));

        try
        {
            task.Wait();
        }
        catch (AggregateException ae)
        {
            foreach (var ex in ae.InnerExceptions)
            {
                // Handle the custom exception.
                if (ex is CustomException)
                {
                    Console.WriteLine(ex.Message);
                }
                // Rethrow any other exception.
                else
                {
                    throw ex;
                }
            }
        }
    }
}
// The example displays the following output:
//        This exception is expected!
Imports System.Threading.Tasks

Module Example
    Public Sub Main()
        Dim task1 = Task.Run(Sub() Throw New CustomException("This exception is expected!"))

        Try
            task1.Wait()
        Catch ae As AggregateException
            For Each ex In ae.InnerExceptions
                ' Handle the custom exception.
                If TypeOf ex Is CustomException Then
                    Console.WriteLine(ex.Message)
                    ' Rethrow any other exception.
                Else
                    Throw ex
                End If
            Next
        End Try
    End Sub
End Module

Class CustomException : Inherits Exception
    Public Sub New(s As String)
        MyBase.New(s)
    End Sub
End Class
' The example displays the following output:
'       This exception is expected!

Yalnızca AggregateException öğesini yakalayarak ve dahili özel durumların hiç birini gözlemeyerek bir işlenmeyen özel durumu önleyebilirsiniz. Ancak, paralel olmayan senaryolarda temel Exception türü yakalamaya benzer olduğundan bunu yapmanızı öneririz. Bir özel durumu yakalayıp bu durumdan kurtulmak için belirli eylemleri yapmazsanız uygulamanız belirsiz bir durumda kalabilir.

Görevin tamamlanmasını beklemek için yöntemini çağırmak Task.Wait istemiyorsanız, aşağıdaki örnekte gösterildiği gibi özel durumu görevin Exception özelliğinden de alabilirsinizAggregateException. Daha fazla bilgi için bu konudaki Task.Exception özelliğini kullanarak özel durumları gözlemleme bölümüne bakın.


public static partial class Program
{
    public static void HandleFour()
    {
        var task = Task.Run(
            () => throw new CustomException("This exception is expected!"));

        while (!task.IsCompleted) { }

        if (task.Status == TaskStatus.Faulted)
        {
            foreach (var ex in task.Exception?.InnerExceptions ?? new(Array.Empty<Exception>()))
            {
                // Handle the custom exception.
                if (ex is CustomException)
                {
                    Console.WriteLine(ex.Message);
                }
                // Rethrow any other exception.
                else
                {
                    throw ex;
                }
            }
        }
    }
}
// The example displays the following output:
//        This exception is expected!
Imports System.Threading.Tasks

Module Example
    Public Sub Main()
        Dim task1 = Task.Run(Sub() Throw New CustomException("This exception is expected!"))

        While Not task1.IsCompleted
        End While

        If task1.Status = TaskStatus.Faulted Then
            For Each ex In task1.Exception.InnerExceptions
                ' Handle the custom exception.
                If TypeOf ex Is CustomException Then
                    Console.WriteLine(ex.Message)
                    ' Rethrow any other exception.
                Else
                    Throw ex
                End If
            Next
        End If
    End Sub
End Module

Class CustomException : Inherits Exception
    Public Sub New(s As String)
        MyBase.New(s)
    End Sub
End Class
' The example displays the following output:
'       This exception is expected!

Dikkat

Yukarıdaki örnek kod, görevin ne zaman tamamlandığını belirlemek için görevin Task.IsCompleted özelliğini yoklayan bir while döngü içerir. Bu, çok verimsiz olduğundan üretim kodunda asla yapılmamalıdır.

Özel durum yayan veya özelliğine Exception erişen bir görevi beklemezseniz, görev çöp olarak toplandığında özel durum .NET özel durum ilkesine göre ilerletilir.

Özel durumların birleştirilmiş iş parçacığına geri dönmesine izin verildiğinde, özel durum yükseltildikten sonra bir görevin bazı öğeleri işlemeye devam etmesi mümkündür.

Not

"Yalnızca Benim Kodum" etkinleştirildiğinde, bazı durumlarda Visual Studio özel durumu oluşturan satırda kırılır ve "özel durum kullanıcı kodu tarafından işlenmez" hata iletisini görüntüler. Bu hata zararsızdır. F5 tuşuna basarak devam edebilir ve bu örneklerde gösterilen özel durum işleme davranışını görebilirsiniz. Visual Studio'nun ilk hatada hata vermesini önlemek için Araçlar, Seçenekler, Hata Ayıklama, Genel altındaki Yalnızca Kodumu Etkinleştir onay kutusunun işaretini kaldırması gerekir.

Eklenen alt görevler ve iç içe Yerleştirilmiş AggregateExceptions

Bir göreve ekli, özel durum oluşturan bir alt görev varsa, o özel durum üst göreve yayılmadan önce bir AggregateException öğesi içine sarmalanır ve bu da o özel durumu çağıran iş parçacığına geri yaymadan önce kendi AggregateException öğesine sarmalar. Böyle durumlarda, InnerExceptions , WaitAnyveya WaitAll yönteminde yakalanan özel durumun özelliğiAggregateException, hataya Task.Waitneden olan özgün özel durumları değil, bir veya daha fazla AggregateException örneği içerir. İç içe AggregateException özel durumları yinelemek zorunda kalmamak için, özelliğinin Flatten özgün özel durumları içermesi için tüm iç içe AggregateException özel durumları AggregateException.InnerExceptions kaldırmak için yöntemini kullanabilirsiniz. Aşağıdaki örnekte, iç içe geçmiş AggregateException örnekleri yalnızca tek bir döngüde düzleştirilip işlenir.


public static partial class Program
{
    public static void FlattenTwo()
    {
        var task = Task.Factory.StartNew(() =>
        {
            var child = Task.Factory.StartNew(() =>
            {
                var grandChild = Task.Factory.StartNew(() =>
                {
                    // This exception is nested inside three AggregateExceptions.
                    throw new CustomException("Attached child2 faulted.");
                }, TaskCreationOptions.AttachedToParent);

                // This exception is nested inside two AggregateExceptions.
                throw new CustomException("Attached child1 faulted.");
            }, TaskCreationOptions.AttachedToParent);
        });

        try
        {
            task.Wait();
        }
        catch (AggregateException ae)
        {
            foreach (var ex in ae.Flatten().InnerExceptions)
            {
                if (ex is CustomException)
                {
                    Console.WriteLine(ex.Message);
                }
                else
                {
                    throw;
                }
            }
        }
    }
}
// The example displays the following output:
//    Attached child1 faulted.
//    Attached child2 faulted.
Imports System.Threading.Tasks

Module Example
    Public Sub Main()
        Dim task1 = Task.Factory.StartNew(Sub()
                                              Dim child1 = Task.Factory.StartNew(Sub()
                                                                                     Dim child2 = Task.Factory.StartNew(Sub()
                                                                                                                            Throw New CustomException("Attached child2 faulted.")
                                                                                                                        End Sub,
                                                                                                                        TaskCreationOptions.AttachedToParent)
                                                                                     Throw New CustomException("Attached child1 faulted.")
                                                                                 End Sub,
                                                                                 TaskCreationOptions.AttachedToParent)
                                          End Sub)

        Try
            task1.Wait()
        Catch ae As AggregateException
            For Each ex In ae.Flatten().InnerExceptions
                If TypeOf ex Is CustomException Then
                    Console.WriteLine(ex.Message)
                Else
                    Throw
                End If
            Next
        End Try
    End Sub
End Module

Class CustomException : Inherits Exception
    Public Sub New(s As String)
        MyBase.New(s)
    End Sub
End Class
' The example displays the following output:
'       Attached child1 faulted.
'       Attached child2 faulted.

Aşağıdaki örnekte gösterildiği gibi, yöntemini kullanarak AggregateException.Flatten tek AggregateException bir örnekte birden çok AggregateException görev tarafından oluşan birden çok örnekten gelen iç özel durumları yeniden oluşturabilirsiniz.

public static partial class Program
{
    public static void TaskExceptionTwo()
    {
        try
        {
            ExecuteTasks();
        }
        catch (AggregateException ae)
        {
            foreach (var e in ae.InnerExceptions)
            {
                Console.WriteLine(
                    "{0}:\n   {1}", e.GetType().Name, e.Message);
            }
        }
    }

    static void ExecuteTasks()
    {
        // Assume this is a user-entered String.
        string path = @"C:\";
        List<Task> tasks = new();

        tasks.Add(Task.Run(() =>
        {
            // This should throw an UnauthorizedAccessException.
            return Directory.GetFiles(
                path, "*.txt",
                SearchOption.AllDirectories);
        }));

        tasks.Add(Task.Run(() =>
        {
            if (path == @"C:\")
            {
                throw new ArgumentException(
                    "The system root is not a valid path.");
            }
            return new string[] { ".txt", ".dll", ".exe", ".bin", ".dat" };
        }));

        tasks.Add(Task.Run(() =>
        {
            throw new NotImplementedException(
                "This operation has not been implemented.");
        }));

        try
        {
            Task.WaitAll(tasks.ToArray());
        }
        catch (AggregateException ae)
        {
            throw ae.Flatten();
        }
    }
}
// The example displays the following output:
//       UnauthorizedAccessException:
//          Access to the path 'C:\Documents and Settings' is denied.
//       ArgumentException:
//          The system root is not a valid path.
//       NotImplementedException:
//          This operation has not been implemented.
Imports System.Collections.Generic
Imports System.IO
Imports System.Threading.Tasks

Module Example
    Public Sub Main()
        Try
            ExecuteTasks()
        Catch ae As AggregateException
            For Each e In ae.InnerExceptions
                Console.WriteLine("{0}:{2}   {1}", e.GetType().Name, e.Message,
                                  vbCrLf)
            Next
        End Try
    End Sub

    Sub ExecuteTasks()
        ' Assume this is a user-entered String.
        Dim path = "C:\"
        Dim tasks As New List(Of Task)

        tasks.Add(Task.Run(Function()
                               ' This should throw an UnauthorizedAccessException.
                               Return Directory.GetFiles(path, "*.txt",
                                                         SearchOption.AllDirectories)
                           End Function))

        tasks.Add(Task.Run(Function()
                               If path = "C:\" Then
                                   Throw New ArgumentException("The system root is not a valid path.")
                               End If
                               Return {".txt", ".dll", ".exe", ".bin", ".dat"}
                           End Function))

        tasks.Add(Task.Run(Sub()
                               Throw New NotImplementedException("This operation has not been implemented.")
                           End Sub))

        Try
            Task.WaitAll(tasks.ToArray)
        Catch ae As AggregateException
            Throw ae.Flatten()
        End Try
    End Sub
End Module
' The example displays the following output:
'       UnauthorizedAccessException:
'          Access to the path 'C:\Documents and Settings' is denied.
'       ArgumentException:
'          The system root is not a valid path.
'       NotImplementedException:
'          This operation has not been implemented.

Ayrılmış alt görevlerden özel durumlar

Varsayılan olarak, özel durumlar ayrılmış olarak oluşturulur. Ayrılmış görevlerde oluşturulan özel durumlar bir üst görev içinde işlenmeli ve yeniden harekete geçirilmelidir; bu özel durumlar eklenen alt görevlerde olduğu şekilde çağıran iş parçacığına geri yayılmaz. En üstteki üst öğe, ayrılmış bir alt öğeden gelen bir özel durumu el ile yeniden oluşturabilir ve bunun bir AggregateException içinde sarmalanıp çağrılan iş parçacığına geri yayılmasına neden olabilir.


public static partial class Program
{
    public static void DetachedTwo()
    {
        var task = Task.Run(() =>
        {
            var nestedTask = Task.Run(
                () => throw new CustomException("Detached child task faulted."));

            // Here the exception will be escalated back to the calling thread.
            // We could use try/catch here to prevent that.
            nestedTask.Wait();
        });

        try
        {
            task.Wait();
        }
        catch (AggregateException ae)
        {
            foreach (var e in ae.Flatten().InnerExceptions)
            {
                if (e is CustomException)
                {
                    Console.WriteLine(e.Message);
                }
            }
        }
    }
}
// The example displays the following output:
//    Detached child task faulted.
Imports System.Threading.Tasks

Module Example
    Public Sub Main()
        Dim task1 = Task.Run(Sub()
                                 Dim nestedTask1 = Task.Run(Sub()
                                                                Throw New CustomException("Detached child task faulted.")
                                                            End Sub)
                                 ' Here the exception will be escalated back to joining thread.
                                 ' We could use try/catch here to prevent that.
                                 nestedTask1.Wait()
                             End Sub)

        Try
            task1.Wait()
        Catch ae As AggregateException
            For Each ex In ae.Flatten().InnerExceptions
                If TypeOf ex Is CustomException Then
                    ' Recover from the exception. Here we just
                    ' print the message for demonstration purposes.
                    Console.WriteLine(ex.Message)
                End If
            Next
        End Try
    End Sub
End Module

Class CustomException : Inherits Exception
    Public Sub New(s As String)
        MyBase.New(s)
    End Sub
End Class
' The example displays the following output:
'       Detached child task faulted.

Bir alt görevdeki özel durumu gözlemek için bir devamlılık kullanıyor olsanız bile, özel durum yine de üst görev tarafından gözlenmelidir.

İşbirliğine dayalı iptali gösteren özel durumlar

Bir görevdeki kullanıcı kodu bir iptal isteğine yanıt verdiğinde, doğru işlem isteğin iletildiği iptal belirtecini geçiren bir OperationCanceledException öğesi oluşturmaktır. Özel durumu yaymadan önce, görev örneği, özel durumdaki belirteci, oluşturulurken geçilen belirteçle karşılaştırır. Aynılarsa, görev, TaskCanceledException öğesine sarmalanmış bir AggregateException öğesi oluşturur ve bu öğe, iç özel durumlar incelenirken görülebilir. Ancak, çağıran iş parçacığı görevde beklemiyorsa, bu özel durum yayılmaz. Daha fazla bilgi için bkz . Görev İptali.

var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
var task = Task.Factory.StartNew(() =>
{
    CancellationToken ct = token;
    while (someCondition)
    {
        // Do some work...
        Thread.SpinWait(50_000);
        ct.ThrowIfCancellationRequested();
    }
},
token);

// No waiting required.
tokenSource.Dispose();
Dim someCondition As Boolean = True
Dim tokenSource = New CancellationTokenSource()
Dim token = tokenSource.Token

Dim task1 = Task.Factory.StartNew(Sub()
                                      Dim ct As CancellationToken = token
                                      While someCondition = True
                                          ' Do some work...
                                          Thread.SpinWait(500000)
                                          ct.ThrowIfCancellationRequested()
                                      End While
                                  End Sub,
                                  token)

İç özel durumları filtrelemek için tanıtıcı yöntemini kullanma

İşlenmiş olarak davranabileceğiniz özel durumları başka bir işleme gerek kalmadan filtrelemek için AggregateException.Handle yöntemini kullanabilirsiniz. yöntemine sağlanan kullanıcı temsilcisinde AggregateException.Handle(Func<Exception,Boolean>) , özel durum türünü, özelliğini Message veya bu konudaki, zararsız olup olmadığını belirlemenize olanak sağlayacak diğer bilgileri inceleyebilirsiniz. Temsilcinin döndürdüğü tüm özel durumlar, yöntem döndürdüğünden false hemen sonra AggregateException.Handle yeni AggregateException bir örnekte yeniden oluşturulur.

Aşağıdaki örnek, koleksiyondaki her özel durumu AggregateException.InnerExceptions inceleyen bu konudaki ilk örnekle işlevsel olarak eşdeğerdir. Bunun yerine, bu özel durum işleyicisi her özel durum için yöntem nesnesini çağırır AggregateException.Handle ve yalnızca örnek olmayan CustomException özel durumları yeniden oluşturur.


public static partial class Program
{
    public static void HandleMethodThree()
    {
        var task = Task.Run(
            () => throw new CustomException("This exception is expected!"));

        try
        {
            task.Wait();
        }
        catch (AggregateException ae)
        {
            // Call the Handle method to handle the custom exception,
            // otherwise rethrow the exception.
            ae.Handle(ex =>
            {
                if (ex is CustomException)
                {
                    Console.WriteLine(ex.Message);
                }
                return ex is CustomException;
            });
        }
    }
}
// The example displays the following output:
//        This exception is expected!
Imports System.Threading.Tasks

Module Example
    Public Sub Main()
        Dim task1 = Task.Run(Sub() Throw New CustomException("This exception is expected!"))

        Try
            task1.Wait()
        Catch ae As AggregateException
            ' Call the Handle method to handle the custom exception,
            ' otherwise rethrow the exception.
            ae.Handle(Function(e)
                          If TypeOf e Is CustomException Then
                              Console.WriteLine(e.Message)
                          End If
                          Return TypeOf e Is CustomException
                      End Function)
        End Try
    End Sub
End Module

Class CustomException : Inherits Exception
    Public Sub New(s As String)
        MyBase.New(s)
    End Sub
End Class
' The example displays the following output:
'       This exception is expected!

Aşağıda, dosyaları numaralandırırken özel durum için özel işleme sağlamak üzere yöntemini kullanan AggregateException.Handle daha eksiksiz bir UnauthorizedAccessException örnek verilmiştir.

public static partial class Program
{
    public static void TaskException()
    {
        // This should throw an UnauthorizedAccessException.
        try
        {
            if (GetAllFiles(@"C:\") is { Length: > 0 } files)
            {
                foreach (var file in files)
                {
                    Console.WriteLine(file);
                }
            }
        }
        catch (AggregateException ae)
        {
            foreach (var ex in ae.InnerExceptions)
            {
                Console.WriteLine(
                    "{0}: {1}", ex.GetType().Name, ex.Message);
            }
        }
        Console.WriteLine();

        // This should throw an ArgumentException.
        try
        {
            foreach (var s in GetAllFiles(""))
            {
                Console.WriteLine(s);
            }
        }
        catch (AggregateException ae)
        {
            foreach (var ex in ae.InnerExceptions)
                Console.WriteLine(
                    "{0}: {1}", ex.GetType().Name, ex.Message);
        }
    }

    static string[] GetAllFiles(string path)
    {
        var task1 =
            Task.Run(() => Directory.GetFiles(
                path, "*.txt",
                SearchOption.AllDirectories));

        try
        {
            return task1.Result;
        }
        catch (AggregateException ae)
        {
            ae.Handle(x =>
            {
                // Handle an UnauthorizedAccessException
                if (x is UnauthorizedAccessException)
                {
                    Console.WriteLine(
                        "You do not have permission to access all folders in this path.");
                    Console.WriteLine(
                        "See your network administrator or try another path.");
                }
                return x is UnauthorizedAccessException;
            });
            return Array.Empty<string>();
        }
    }
}
// The example displays the following output:
//       You do not have permission to access all folders in this path.
//       See your network administrator or try another path.
//
//       ArgumentException: The path is not of a legal form.
Imports System.IO
Imports System.Threading.Tasks

Module Example
    Public Sub Main()
        ' This should throw an UnauthorizedAccessException.
        Try
            Dim files = GetAllFiles("C:\")
            If files IsNot Nothing Then
                For Each file In files
                    Console.WriteLine(file)
                Next
            End If
        Catch ae As AggregateException
            For Each ex In ae.InnerExceptions
                Console.WriteLine("{0}: {1}", ex.GetType().Name, ex.Message)
            Next
        End Try
        Console.WriteLine()

        ' This should throw an ArgumentException.
        Try
            For Each s In GetAllFiles("")
                Console.WriteLine(s)
            Next
        Catch ae As AggregateException
            For Each ex In ae.InnerExceptions
                Console.WriteLine("{0}: {1}", ex.GetType().Name, ex.Message)
            Next
        End Try
        Console.WriteLine()
    End Sub

    Function GetAllFiles(ByVal path As String) As String()
        Dim task1 = Task.Run(Function()
                                 Return Directory.GetFiles(path, "*.txt",
                                                           SearchOption.AllDirectories)
                             End Function)
        Try
            Return task1.Result
        Catch ae As AggregateException
            ae.Handle(Function(x)
                          ' Handle an UnauthorizedAccessException
                          If TypeOf x Is UnauthorizedAccessException Then
                              Console.WriteLine("You do not have permission to access all folders in this path.")
                              Console.WriteLine("See your network administrator or try another path.")
                          End If
                          Return TypeOf x Is UnauthorizedAccessException
                      End Function)
        End Try
        Return Array.Empty(Of String)()
    End Function
End Module
' The example displays the following output:
'       You do not have permission to access all folders in this path.
'       See your network administrator or try another path.
'
'       ArgumentException: The path is not of a legal form.

Task.Exception özelliğini kullanarak özel durumları gözlemleme

Eğer bir görev TaskStatus.Faulted durumunda tamamlanırsa, hatayı tam olarak hangi özel durumun oluşturduğunu bulmak için Exception özelliği incelenebilir. Exception özelliğini incelemenin iyi bir yolu, aşağıdaki örnekte gösterildiği gibi yalnızca öncül görev hata verirse çalışan bir devamlılık kullanmaktır.


public static partial class Program
{
    public static void ExceptionPropagationTwo()
    {
        _ = Task.Run(
            () => throw new CustomException("task1 faulted."))
            .ContinueWith(_ =>
            {
                if (_.Exception?.InnerException is { } inner)
                {
                    Console.WriteLine("{0}: {1}",
                        inner.GetType().Name,
                        inner.Message);
                }
            }, 
            TaskContinuationOptions.OnlyOnFaulted);
        
        Thread.Sleep(500);
    }
}
// The example displays output like the following:
//        CustomException: task1 faulted.
Imports System.Threading
Imports System.Threading.Tasks

Module Example
    Public Sub Main()
        Dim task1 = Task.Factory.StartNew(Sub()
                                              Throw New CustomException("task1 faulted.")
                                          End Sub).
                    ContinueWith(Sub(t)
                                     Console.WriteLine("{0}: {1}",
                                                     t.Exception.InnerException.GetType().Name,
                                                     t.Exception.InnerException.Message)
                                 End Sub, TaskContinuationOptions.OnlyOnFaulted)

        Thread.Sleep(500)
    End Sub
End Module

Class CustomException : Inherits Exception
    Public Sub New(s As String)
        MyBase.New(s)
    End Sub
End Class
' The example displays output like the following:
'       CustomException: task1 faulted.

Anlamlı bir uygulamada, devamlılık temsilcisi özel durumla ilgili ayrıntılı bilgileri günlüğe kaydedebilir ve büyük olasılıkla özel durumdan kurtarmak için yeni görevler oluşturabiliyordu. Bir görev hata verirse, aşağıdaki ifadeler özel durum oluşturur:

  • await task
  • task.Wait()
  • task.Result
  • task.GetAwaiter().GetResult()

Oluşan özel durumları işlemek ve gözlemlemek için deyimini try-catch kullanın. Alternatif olarak özelliğine erişerek özel durumu gözlemleyin Task.Exception .

Önemli

AggregateException aşağıdaki ifadeler kullanılırken açıkça yakalanamaz:

  • await task
  • task.GetAwaiter().GetResult()

UnobservedTaskException olayı

Güvenilmeyen eklentileri barındırmak gibi bazı senaryolarda, zararsız özel durumlar sık gerçekleşebilir ve hepsini el ile gözlemek çok zor olabilir. Bu durumlarda, TaskScheduler.UnobservedTaskException olayını işleyebilirsiniz. İşleyicinize geçirilen System.Threading.Tasks.UnobservedTaskExceptionEventArgs örneği, gözlemlenmemiş özel durumun birleşen iş parçacığına geri yayılmasını önlemek için kullanılabilir.

Ayrıca bkz.