작업 취소Task Cancellation

System.Threading.Tasks.TaskSystem.Threading.Tasks.Task<TResult> 클래스는 .NET Framework에서 취소 토큰을 사용하는 방법으로 취소 기능을 지원합니다.The System.Threading.Tasks.Task and System.Threading.Tasks.Task<TResult> classes support cancellation through the use of cancellation tokens in the .NET Framework. 자세한 내용은 관리되는 스레드의 취소를 참조하세요.For more information, see Cancellation in Managed Threads. 작업 클래스에서 취소하려면 취소할 수 있는 작업을 나타내는 사용자 대리자와 취소를 요청한 코드 간의 협조가 필요합니다.In the Task classes, cancellation involves cooperation between the user delegate, which represents a cancelable operation and the code that requested the cancellation. 성공적으로 취소하려면 CancellationTokenSource.Cancel 메서드를 호출하는 요청 코드와 적절한 시간에 이루어지는 작업을 종료하는 사용자 대리자가 필요합니다.A successful cancellation involves the requesting code calling the CancellationTokenSource.Cancel method, and the user delegate terminating the operation in a timely manner. 다음 방법 중 하나를 사용하여 작업을 종료할 수 있습니다.You can terminate the operation by using one of these options:

  • 단순히 대리자에서 반환합니다.By simply returning from the delegate. 대부분의 경우에는 이 방법으로 충분하지만 이 방법으로 취소된 작업 인스턴스는 TaskStatus.RanToCompletion 상태가 아니라 TaskStatus.Canceled 상태로 전환됩니다.In many scenarios this is sufficient; however, a task instance that is canceled in this way transitions to the TaskStatus.RanToCompletion state, not to the TaskStatus.Canceled state.

  • OperationCanceledException 을 throw하고 취소가 요청된 토큰을 전달합니다.By throwing a OperationCanceledException and passing it the token on which cancellation was requested. 이렇게 하려면 ThrowIfCancellationRequested 메서드를 사용하는 것이 좋습니다.The preferred way to do this is to use the ThrowIfCancellationRequested method. 이 방법으로 취소된 작업은 Canceled 상태로 전환되므로 호출 코드에서는 이 상태를 통해 작업이 취소 요청에 응답했음을 확인할 수 있습니다.A task that is canceled in this way transitions to the Canceled state, which the calling code can use to verify that the task responded to its cancellation request.

다음 예제에서는 예외를 throw하는 작업 취소의 기본적인 패턴을 보여 줍니다.The following example shows the basic pattern for task cancellation that throws the exception. 토큰은 사용자 대리자와 작업 인스턴스 자체에 전달됩니다.Note that the token is passed to the user delegate and to the task instance itself.

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

자세한 예제는 방법: 작업 및 해당 자식 취소를 참조하세요.For a more complete example, see How to: Cancel a Task and Its Children.

작업 인스턴스는 사용자 코드에서 throw된 OperationCanceledException 이 관찰될 경우 예외의 토큰을 관련 토큰, 즉 해당 작업을 만든 API에 전달된 토큰과 비교합니다.When a task instance observes an OperationCanceledException thrown by user code, it compares the exception's token to its associated token (the one that was passed to the API that created the Task). 두 토큰이 동일하고 토큰의 IsCancellationRequested 속성이 true를 반환하면 해당 작업은 이를 취소 승인으로 해석하고 Canceled 상태로 전환됩니다.If they are the same and the token's IsCancellationRequested property returns true, the task interprets this as acknowledging cancellation and transitions to the Canceled state. Wait 또는 WaitAll 메서드를 사용하여 작업이 완료될 때까지 대기하지 않는 경우 해당 작업은 단순히 상태를 Canceled로 설정합니다.If you do not use a Wait or WaitAll method to wait for the task, then the task just sets its status to Canceled.

Canceled 상태로 전환되는 작업에서 대기 중인 경우에는 System.Threading.Tasks.TaskCanceledException 예외가 AggregateException 예외에 래핑된 상태로 throw됩니다.If you are waiting on a Task that transitions to the Canceled state, a System.Threading.Tasks.TaskCanceledException exception (wrapped in an AggregateException exception) is thrown. 이 예외는 오류가 아니라 성공적인 취소를 나타냅니다.Note that this exception indicates successful cancellation instead of a faulty situation. 따라서 작업의 Exception 속성은 null을 반환합니다.Therefore, the task's Exception property returns null.

토큰의 IsCancellationRequested 속성이 false를 반환하거나 예외의 토큰이 작업의 토큰과 일치하지 않는 경우 OperationCanceledException 은 일반적인 예외처럼 처리되므로 작업이 Faulted 상태로 전환됩니다.If the token's IsCancellationRequested property returns false or if the exception's token does not match the Task's token, the OperationCanceledException is treated like a normal exception, causing the Task to transition to the Faulted state. 또한 다른 예외가 있는 경우에도 작업이 Faulted 상태로 전환됩니다.Also note that the presence of other exceptions will also cause the Task to transition to the Faulted state. 완료된 작업의 상태는 Status 속성에서 가져올 수 있습니다.You can get the status of the completed task in the Status property.

취소를 요청한 후에도 작업에서 일부 항목의 처리를 계속 진행할 수 있습니다.It is possible that a task may continue to process some items after cancellation is requested.

참고 항목See also