작업 취소

System.Threading.Tasks.TaskSystem.Threading.Tasks.Task<TResult> 클래스는 취소 토큰을 사용하여 취소를 지원합니다. 자세한 내용은 관리되는 스레드의 취소를 참조하세요. 작업 클래스에서 취소하려면 취소할 수 있는 작업을 나타내는 사용자 대리자와 취소를 요청한 코드 간의 협조가 필요합니다. 성공적으로 취소하려면 CancellationTokenSource.Cancel 메서드를 호출하는 요청 코드와 적절한 시간에 작업을 종료하는 사용자 대리자가 필요합니다. 다음 방법 중 하나를 사용하여 작업을 종료할 수 있습니다.

  • 대리자에서 반환합니다. 많은 시나리오에서는 이 옵션으로 충분합니다. 그러나 이 방법으로 취소된 작업 인스턴스는 TaskStatus.Canceled 상태가 아니라 TaskStatus.RanToCompletion 상태로 전환합니다.

  • OperationCanceledException을 throw하고 취소가 요청된 토큰을 전달합니다. 수행하려면 ThrowIfCancellationRequested 메서드를 사용하는 것이 좋습니다. 이 방법으로 취소된 작업은 Canceled 상태로 전환되므로 호출 코드에서는 이 상태를 통해 작업이 취소 요청에 응답했음을 확인할 수 있습니다.

다음 예제에서는 예외를 throw하는 작업 취소의 기본적인 패턴을 보여줍니다.

참고

토큰은 사용자 대리자와 작업 인스턴스에 전달됩니다.

using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var tokenSource2 = new CancellationTokenSource();
        CancellationToken ct = tokenSource2.Token;

        var task = Task.Run(() =>
        {
            // Were we already canceled?
            ct.ThrowIfCancellationRequested();

            bool moreToDo = true;
            while (moreToDo)
            {
                // Poll on this property if you have to do
                // other cleanup before throwing.
                if (ct.IsCancellationRequested)
                {
                    // Clean up here, then...
                    ct.ThrowIfCancellationRequested();
                }
            }
        }, tokenSource2.Token); // Pass same token to Task.Run.

        tokenSource2.Cancel();

        // Just continue on this thread, or await with try-catch:
        try
        {
            await task;
        }
        catch (OperationCanceledException e)
        {
            Console.WriteLine($"{nameof(OperationCanceledException)} thrown with message: {e.Message}");
        }
        finally
        {
            tokenSource2.Dispose();
        }

        Console.ReadKey();
    }
}
Imports System.Threading
Imports System.Threading.Tasks

Module Test
    Sub Main()
        Dim tokenSource2 As New CancellationTokenSource()
        Dim ct As CancellationToken = tokenSource2.Token

        Dim t2 = Task.Factory.StartNew(Sub()
                                           ' Were we already canceled?
                                           ct.ThrowIfCancellationRequested()

                                           Dim moreToDo As Boolean = True
                                           While moreToDo = True
                                               ' Poll on this property if you have to do
                                               ' other cleanup before throwing.
                                               If ct.IsCancellationRequested Then

                                                   ' Clean up here, then...
                                                   ct.ThrowIfCancellationRequested()
                                               End If

                                           End While
                                       End Sub _
        , tokenSource2.Token) ' Pass same token to StartNew.

        ' Cancel the task.
        tokenSource2.Cancel()

        ' Just continue on this thread, or Wait/WaitAll with try-catch:
        Try
            t2.Wait()

        Catch e As AggregateException

            For Each item In e.InnerExceptions
                Console.WriteLine(e.Message & " " & item.Message)
            Next
        Finally
            tokenSource2.Dispose()
        End Try

        Console.ReadKey()
    End Sub
End Module

전체 예제는 방법: 작업 및 해당 자식 취소를 참조하세요.

작업 인스턴스는 사용자 코드에서 throw된 OperationCanceledException이 관찰될 경우 예외의 토큰을 관련 토큰 즉, 해당 작업을 만든 API에 전달된 토큰과 비교합니다. 두 토큰이 동일하고 토큰의 IsCancellationRequested 속성이 true를 반환하면 해당 작업은 이를 취소 승인으로 해석하고 Canceled 상태로 전환합니다. Wait 또는 WaitAll 메서드를 사용하여 작업이 완료될 때까지 대기하지 않는 경우 해당 작업은 단순히 상태를 Canceled로 설정합니다.

Canceled 상태로 전환되는 작업에서 대기 중인 경우에는 System.Threading.Tasks.TaskCanceledException 예외가 AggregateException 예외에 래핑된 상태로 throw됩니다. 이 예외는 오류가 아니라 성공적인 취소를 나타냅니다. 따라서 작업의 Exception 속성은 null을 반환합니다.

토큰의 IsCancellationRequested 속성이 false를 반환하거나 예외의 토큰이 작업의 토큰과 일치하지 않는 경우 OperationCanceledException은 일반적인 예외처럼 처리되므로 작업이 Faulted 상태로 전환합니다. 또한 다른 예외가 있는 경우에도 작업이 Faulted 상태로 전환합니다. 완료된 작업의 상태는 Status 속성에서 가져올 수 있습니다.

취소를 요청한 후에도 작업에서 일부 항목의 처리를 계속 진행할 수 있습니다.

참조