관리되는 스레드의 취소Cancellation in Managed Threads

.NET Framework 4부터 .NET Framework에서는 비동기 또는 장기 실행 비동기 작업의 협조적 취소를 위한 통합 모델을 사용합니다.Starting with the .NET Framework 4, the .NET Framework uses a unified model for cooperative cancellation of asynchronous or long-running synchronous operations. 이 모델은 취소 토큰이라는 경량 개체에 기반을 둡니다.This model is based on a lightweight object called a cancellation token. 취소할 수 있는 작업 하나 이상을 호출하는 개체가 새 스레드나 작업 등을 만드는 방식으로 토큰을 각 작업에 전달합니다.The object that invokes one or more cancelable operations, for example by creating new threads or tasks, passes the token to each operation. 개별 작업이 토큰 복사본을 다시 다른 작업에 전달할 수 있습니다.Individual operations can in turn pass copies of the token to other operations. 나중에 토큰을 만든 개체가 해당 토큰을 사용하여 관련 작업이 수행 중인 작업을 중지하도록 요청할 수 있습니다.At some later time, the object that created the token can use it to request that the operations stop what they are doing. 요청 개체만 취소 요청을 실행할 수 있고 각 수신기는 적절한 시간에 적절한 방식으로 요청을 알리고 요청에 응답해야 합니다.Only the requesting object can issue the cancellation request, and each listener is responsible for noticing the request and responding to it in an appropriate and timely manner.

협조적 취소 모델을 구현하는 일반적인 패턴은 다음과 같습니다.The general pattern for implementing the cooperative cancellation model is:

  • 개별 취소 토큰을 관리하고 토큰에 취소 알림을 보내는 CancellationTokenSource 개체를 인스턴스화합니다.Instantiate a CancellationTokenSource object, which manages and sends cancellation notification to the individual cancellation tokens.

  • CancellationTokenSource.Token 속성에서 반환된 토큰을 취소를 수신 대기하는 각 작업이나 스레드에 전달합니다.Pass the token returned by the CancellationTokenSource.Token property to each task or thread that listens for cancellation.

  • 각 작업이나 스레드가 취소에 응답하는 메커니즘을 제공합니다.Provide a mechanism for each task or thread to respond to cancellation.

  • CancellationTokenSource.Cancel 메서드를 호출하여 취소 알림을 제공합니다.Call the CancellationTokenSource.Cancel method to provide notification of cancellation.

중요

CancellationTokenSource 클래스가 IDisposable 인터페이스를 구현합니다.The CancellationTokenSource class implements the IDisposable interface. 취소 토큰 소스 사용을 마치면 CancellationTokenSource.Dispose 메서드를 호출하여 토큰에 포함된 관리되지 않는 리소스를 해제해야 합니다.You should be sure to call the CancellationTokenSource.Dispose method when you have finished using the cancellation token source to free any unmanaged resources it holds.

다음 그림에서는 토큰 소스와 모든 토큰 복사본의 관계를 보여 줍니다.The following illustration shows the relationship between a token source and all the copies of its token.

CancellationTokenSource 및 cancellation 토큰CancellationTokenSource and cancellation tokens

새 취소 모델을 통해 취소 인식 애플리케이션 및 라이브러리를 더 쉽게 만들 수 있고 이 모델은 다음 기능을 지원합니다.The new cancellation model makes it easier to create cancellation-aware applications and libraries, and it supports the following features:

  • 취소는 협조적이고 수신기에 적용되지 않습니다.Cancellation is cooperative and is not forced on the listener. 수신기는 취소 요청에 대한 응답으로 정상적으로 종료하는 방법을 결정합니다.The listener determines how to gracefully terminate in response to a cancellation request.

  • 요청은 수신 대기와 다릅니다.Requesting is distinct from listening. 취소할 수 있는 작업을 호출하는 개체는 취소가 있더라도 취소가 요청되는 시점을 제어할 수 있습니다.An object that invokes a cancelable operation can control when (if ever) cancellation is requested.

  • 요청 개체는 단 하나의 메서드 호출을 통해 모든 토큰 복사본에 대해 취소 요청을 실행합니다.The requesting object issues the cancellation request to all copies of the token by using just one method call.

  • 수신기는 여러 토큰을 하나의 연결된 토큰으로 결합하여 동시에 수신 대기할 수 있습니다.A listener can listen to multiple tokens simultaneously by joining them into one linked token.

  • 사용자 코드는 라이브러리 코드에서 취소 요청을 인식하고 이 요청에 응답할 수 있고, 라이브러리 코드는 사용자 코드에서 취소 요청을 인식하고 이 요청에 응답할 수 있습니다.User code can notice and respond to cancellation requests from library code, and library code can notice and respond to cancellation requests from user code.

  • 수신기는 대기 핸들에 대한 폴링, 콜백 등록 또는 대기를 통해 취소 요청에 대한 알림을 받을 수 있습니다.Listeners can be notified of cancellation requests by polling, callback registration, or waiting on wait handles.

취소 형식Cancellation Types

취소 프레임워크는 다음 표에 나열된 관련 형식 집합으로 구현됩니다.The cancellation framework is implemented as a set of related types, which are listed in the following table.

형식 이름Type name 설명Description
CancellationTokenSource 취소 토큰을 만들고 해당 토큰의 모든 복사본에 대한 취소 요청을 실행하는 개체입니다.Object that creates a cancellation token, and also issues the cancellation request for all copies of that token.
CancellationToken 일반적으로 메서드 매개 변수로 수신기 하나 이상에 전달되는 경량 값 형식입니다.Lightweight value type passed to one or more listeners, typically as a method parameter. 수신기는 핸들을 폴링, 콜백 또는 대기하여 토큰의 IsCancellationRequested 속성 값을 모니터링합니다.Listeners monitor the value of the IsCancellationRequested property of the token by polling, callback, or wait handle.
OperationCanceledException 이 예외 생성자의 오버로드는 CancellationToken을 매개 변수로 허용합니다.Overloads of this exception's constructor accept a CancellationToken as a parameter. 수신기는 선택적으로 이 예외를 throw하여 취소의 출처를 확인하고 취소 요청에 응답했다는 것을 다른 수신기에 알립니다.Listeners can optionally throw this exception to verify the source of the cancellation and notify others that it has responded to a cancellation request.

새 취소 모델은 여러 가지 형식으로 .NET Framework에 통합되었습니다.The new cancellation model is integrated into the .NET Framework in several types. 가장 중요한 형식은 System.Threading.Tasks.Parallel, System.Threading.Tasks.Task, System.Threading.Tasks.Task<TResult>System.Linq.ParallelEnumerable입니다.The most important ones are System.Threading.Tasks.Parallel, System.Threading.Tasks.Task, System.Threading.Tasks.Task<TResult> and System.Linq.ParallelEnumerable. 모든 새 라이브러리 및 애플리케이션 코드에 대해 이 새 취소 모델을 사용하는 것이 좋습니다.We recommend that you use this new cancellation model for all new library and application code.

코드 예제Code Example

다음 예제에서는 요청 개체가 CancellationTokenSource 개체를 만들고 Token 속성을 취소 가능한 작업에 전달합니다.In the following example, the requesting object creates a CancellationTokenSource object, and then passes its Token property to the cancelable operation. 요청을 수신하는 작업에서는 폴링을 통해 토큰의 IsCancellationRequested 속성 값을 모니터링합니다.The operation that receives the request monitors the value of the IsCancellationRequested property of the token by polling. 값이 true가 되면 수신기가 적절한 방식이더라도 종료될 수 있습니다.When the value becomes true, the listener can terminate in whatever manner is appropriate. 이 예제에서는 대부분 경우에 모두 필요한 메서드가 종료됩니다.In this example, the method just exits, which is all that is required in many cases.

참고

예제에서는 QueueUserWorkItem 메서드를 사용하여 새 취소 프레임워크가 기존 API와 호환된다는 것을 보여 줍니다.The example uses the QueueUserWorkItem method to demonstrate that the new cancellation framework is compatible with legacy APIs. 새로운 권장 System.Threading.Tasks.Task 형식을 사용하는 예에 대해서는 방법: 작업 및 해당 자식 취소를 참조하세요.For an example that uses the new, preferred System.Threading.Tasks.Task type, see How to: Cancel a Task and Its Children.

using System;
using System.Threading;

public class Example
{
   public static void Main()
   {
      // Create the token source.
      CancellationTokenSource cts = new CancellationTokenSource();

      // Pass the token to the cancelable operation.
      ThreadPool.QueueUserWorkItem(new WaitCallback(DoSomeWork), cts.Token);
      Thread.Sleep(2500);

      // Request cancellation.
      cts.Cancel();
      Console.WriteLine("Cancellation set in token source...");
      Thread.Sleep(2500);
      // Cancellation should have happened, so call Dispose.
      cts.Dispose();
   }

   // Thread 2: The listener
   static void DoSomeWork(object obj)
   {
      CancellationToken token = (CancellationToken)obj;

      for (int i = 0; i < 100000; i++) {
         if (token.IsCancellationRequested)
         {
            Console.WriteLine("In iteration {0}, cancellation has been requested...",
                              i + 1);
            // Perform cleanup if necessary.
            //...
            // Terminate the operation.
            break;
         }
         // Simulate some work.
         Thread.SpinWait(500000);
      }
   }
}
// The example displays output like the following:
//       Cancellation set in token source...
//       In iteration 1430, cancellation has been requested...
Imports System.Threading

Module Example
   Public Sub Main()
      ' Create the token source.
      Dim cts As New CancellationTokenSource()

      ' Pass the token to the cancelable operation.
      ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf DoSomeWork), cts.Token)
      Thread.Sleep(2500)
        
      ' Request cancellation by setting a flag on the token.
      cts.Cancel()
      Console.WriteLine("Cancellation set in token source...")
      Thread.Sleep(2500)
      ' Cancellation should have happened, so call Dispose.
      cts.Dispose()
   End Sub

   ' Thread 2: The listener
   Sub DoSomeWork(ByVal obj As Object)
      Dim token As CancellationToken = CType(obj, CancellationToken)
      
      For i As Integer = 0 To 1000000
         If token.IsCancellationRequested Then
            Console.WriteLine("In iteration {0}, cancellation has been requested...",
                              i + 1)
            ' Perform cleanup if necessary.
            '...
            ' Terminate the operation.
            Exit For
         End If
      
         ' Simulate some work.
         Thread.SpinWait(500000)
      Next
   End Sub
End Module
' The example displays output like the following:
'       Cancellation set in token source...
'       In iteration 1430, cancellation has been requested...

작업 취소 대 개체 취소Operation Cancellation Versus Object Cancellation

새 취소 프레임워크에서 취소는 개체가 아니라 작업을 나타냅니다.In the new cancellation framework, cancellation refers to operations, not objects. 취소 요청은 필요한 정리가 수행되고 나서 가능하면 즉시 작업이 중지되어야 함을 의미합니다.The cancellation request means that the operation should stop as soon as possible after any required cleanup is performed. 취소 토큰 하나가 “취소할 수 있는 작업" 하나를 나타내야 하지만 해당 작업은 프로그램에서 구현될 수 있습니다.One cancellation token should refer to one "cancelable operation," however that operation may be implemented in your program. 토큰의 IsCancellationRequested 속성이 true로 설정되고 나면 false로 재설정될 수 없습니다.After the IsCancellationRequested property of the token has been set to true, it cannot be reset to false. 따라서 취소 토큰이 취소된 후에는 해당 토큰을 다시 사용할 수 없습니다.Therefore, cancellation tokens cannot be reused after they have been canceled.

개체 취소 메커니즘이 필요하면 다음 예제와 같이 CancellationToken.Register 메서드를 호출하여 작업 취소 메커니즘을 기반으로 개체 취소 메커니즘을 적용할 수 있습니다.If you require an object cancellation mechanism, you can base it on the operation cancellation mechanism by calling the CancellationToken.Register method, as shown in the following example.

using System;
using System.Threading;

class CancelableObject
{
   public string id;
   
   public CancelableObject(string id)
   {
      this.id = id;
   }
   
   public void Cancel() 
   { 
      Console.WriteLine("Object {0} Cancel callback", id);
      // Perform object cancellation here.
   }
}

public class Example
{
   public static void Main()
   {
      CancellationTokenSource cts = new CancellationTokenSource();
      CancellationToken token = cts.Token;

      // User defined Class with its own method for cancellation
      var obj1 = new CancelableObject("1");
      var obj2 = new CancelableObject("2");
      var obj3 = new CancelableObject("3");

      // Register the object's cancel method with the token's
      // cancellation request.
      token.Register(() => obj1.Cancel());
      token.Register(() => obj2.Cancel());
      token.Register(() => obj3.Cancel());

      // Request cancellation on the token.
      cts.Cancel();
      // Call Dispose when we're done with the CancellationTokenSource.
      cts.Dispose();
   }
}
// The example displays the following output:
//       Object 3 Cancel callback
//       Object 2 Cancel callback
//       Object 1 Cancel callback
Imports System.Threading

Class CancelableObject
   Public id As String
   
   Public Sub New(id As String)
      Me.id = id
   End Sub
   
   Public Sub Cancel() 
      Console.WriteLine("Object {0} Cancel callback", id)
      ' Perform object cancellation here.
   End Sub
End Class

Module Example
   Public Sub Main()
        Dim cts As New CancellationTokenSource()
        Dim token As CancellationToken = cts.Token

        ' User defined Class with its own method for cancellation
        Dim obj1 As New CancelableObject("1")
        Dim obj2 As New CancelableObject("2")
        Dim obj3 As New CancelableObject("3")

        ' Register the object's cancel method with the token's
        ' cancellation request.
        token.Register(Sub() obj1.Cancel())
        token.Register(Sub() obj2.Cancel())
        token.Register(Sub() obj3.Cancel())

        ' Request cancellation on the token.
        cts.Cancel()
        ' Call Dispose when we're done with the CancellationTokenSource.
        cts.Dispose()
   End Sub
End Module
' The example displays output like the following:
'       Object 3 Cancel callback
'       Object 2 Cancel callback
'       Object 1 Cancel callback

개체가 동시 취소 가능 작업을 두 개 이상 지원하면 개별 토큰을 개별 취소 가능한 작업에 입력으로 전달합니다.If an object supports more than one concurrent cancelable operation, pass a separate token as input to each distinct cancelable operation. 이런 방식으로 다른 작업에 영향을 미치지 않고 작업을 취소할 수 있습니다.That way, one operation can be cancelled without affecting the others.

취소 요청 수신 대기 및 응답Listening and Responding to Cancellation Requests

사용자 대리자에서 취소 가능한 작업의 구현자는 취소 요청에 대한 응답으로 작업을 종료하는 방법을 결정합니다.In the user delegate, the implementer of a cancelable operation determines how to terminate the operation in response to a cancellation request. 대부분 경우에 사용자 대리자는 필요한 정리를 수행하고 즉시 반환될 수 있습니다.In many cases, the user delegate can just perform any required cleanup and then return immediately.

그러나 더 복잡한 경우에 사용자 대리자가 취소가 발생했다는 정보를 라이브러리 코드에 알려야 할 수 있습니다.However, in more complex cases, it might be necessary for the user delegate to notify library code that cancellation has occurred. 이 경우 작업을 종료하는 올바른 방법은 OperationCanceledException을 throw하는 ThrowIfCancellationRequested 메서드를 대리자가 호출하는 것입니다.In such cases, the correct way to terminate the operation is for the delegate to call the ThrowIfCancellationRequested, method, which will cause an OperationCanceledException to be thrown. 라이브러리 코드는 사용자 대리자 스레드에서 이 예외를 catch하고 예외의 토큰을 검사하여 예외가 협조적 취소를 나타내는지, 아니면 다른 예외적인 상황인지를 결정합니다.Library code can catch this exception on the user delegate thread and examine the exception's token to determine whether the exception indicates cooperative cancellation or some other exceptional situation.

Task 클래스는 이 방식으로 OperationCanceledException을 처리합니다.The Task class handles OperationCanceledException in this way. 자세한 내용은 작업 취소를 참조하세요.For more information, see Task Cancellation.

폴링으로 수신 대기Listening by Polling

루핑되거나 재귀적으로 사용되는 장기 실행 계산의 경우 CancellationToken.IsCancellationRequested 속성 값을 주기적으로 폴링하여 취소 요청을 수신 대기할 수 있습니다.For long-running computations that loop or recurse, you can listen for a cancellation request by periodically polling the value of the CancellationToken.IsCancellationRequested property. 값이 true이면 메서드가 가능한 한 빠르게 정리 및 종료되어야 합니다.If its value is true, the method should clean up and terminate as quickly as possible. 최적 폴링 빈도는 애플리케이션 형식에 따라 다릅니다.The optimal frequency of polling depends on the type of application. 특정 프로그램에 대한 최적 폴링 빈도는 개발자가 결정할 수 있습니다.It is up to the developer to determine the best polling frequency for any given program. 폴링 자체는 성능에 큰 영향을 미치지 않습니다.Polling itself does not significantly impact performance. 다음 예제에서는 한 가지 가능한 폴링 방법을 보여 줍니다.The following example shows one possible way to poll.

static void NestedLoops(Rectangle rect, CancellationToken token)
{
   for (int x = 0; x < rect.columns && !token.IsCancellationRequested; x++) {
      for (int y = 0; y < rect.rows; y++) {
         // Simulating work.
         Thread.SpinWait(5000);
         Console.Write("{0},{1} ", x, y);
      }

      // Assume that we know that the inner loop is very fast.
      // Therefore, checking once per row is sufficient.
      if (token.IsCancellationRequested) {
         // Cleanup or undo here if necessary...
         Console.WriteLine("\r\nCancelling after row {0}.", x);
         Console.WriteLine("Press any key to exit.");
         // then...
         break;
         // ...or, if using Task:
         // token.ThrowIfCancellationRequested();
      }
   }
}
Shared Sub NestedLoops(ByVal rect As Rectangle, ByVal token As CancellationToken)
    For x As Integer = 0 To rect.columns
        For y As Integer = 0 To rect.rows
            ' Simulating work.
            Thread.SpinWait(5000)
            Console.Write("0' end block,1' end block ", x, y)
        Next

        ' Assume that we know that the inner loop is very fast.
        ' Therefore, checking once per row is sufficient.
        If token.IsCancellationRequested = True Then
            ' Cleanup or undo here if necessary...
            Console.WriteLine(vbCrLf + "Cancelling after row 0' end block.", x)
            Console.WriteLine("Press any key to exit.")
            ' then...
            Exit For
            ' ...or, if using Task:
            ' token.ThrowIfCancellationRequested()
        End If
    Next
End Sub

자세한 예제는 방법: 폴링을 통해 취소 요청 수신 대기를 참조하세요.For a more complete example, see How to: Listen for Cancellation Requests by Polling.

콜백을 등록하여 수신 대기Listening by Registering a Callback

일부 작업은 적절한 시기에 취소 토큰의 값을 확인할 수 없는 방식으로 차단될 수 있습니다.Some operations can become blocked in such a way that they cannot check the value of the cancellation token in a timely manner. 이러한 경우에는 취소 요청이 수신될 때 메서드를 차단 해제하는 콜백 메서드를 등록할 수 있습니다.For these cases, you can register a callback method that unblocks the method when a cancellation request is received.

Register 메서드는 특히 이 목적으로 사용되는 CancellationTokenRegistration 개체를 반환합니다.The Register method returns a CancellationTokenRegistration object that is used specifically for this purpose. 다음 예제에서는 Register 메서드를 사용하여 비동기 웹 요청을 취소하는 방법을 보여 줍니다.The following example shows how to use the Register method to cancel an asynchronous Web request.

using System;
using System.Net;
using System.Threading;

class Example
{
    static void Main()
    {
        CancellationTokenSource cts = new CancellationTokenSource();

        StartWebRequest(cts.Token);

        // cancellation will cause the web 
        // request to be cancelled
        cts.Cancel();
    }

    static void StartWebRequest(CancellationToken token)
    {
        WebClient wc = new WebClient();
        wc.DownloadStringCompleted += (s, e) => Console.WriteLine("Request completed.");

        // Cancellation on the token will 
        // call CancelAsync on the WebClient.
        token.Register(() =>
        {
            wc.CancelAsync();
            Console.WriteLine("Request cancelled!");
        });

        Console.WriteLine("Starting request.");
        wc.DownloadStringAsync(new Uri("http://www.contoso.com"));
    }
}
Imports System.Net
Imports System.Threading

Class Example
    Private Shared Sub Main()
        Dim cts As New CancellationTokenSource()

        StartWebRequest(cts.Token)

        ' cancellation will cause the web 
        ' request to be cancelled
        cts.Cancel()
    End Sub

    Private Shared Sub StartWebRequest(token As CancellationToken)
        Dim wc As New WebClient()
        wc.DownloadStringCompleted += Function(s, e) Console.WriteLine("Request completed.")

        ' Cancellation on the token will 
        ' call CancelAsync on the WebClient.
        token.Register(Function() 
        wc.CancelAsync()
        Console.WriteLine("Request cancelled!")

End Function)

        Console.WriteLine("Starting request.")
        wc.DownloadStringAsync(New Uri("http://www.contoso.com"))
    End Sub
End Class

CancellationTokenRegistration 개체는 스레드 동기화를 관리하고 콜백이 정확한 시점에 실행을 중지하는지 확인합니다.The CancellationTokenRegistration object manages thread synchronization and ensures that the callback will stop executing at a precise point in time.

시스템 응답성을 확인하고 교착 상태를 방지하려면 콜백을 등록할 때 다음 지침을 따라야 합니다.In order to ensure system responsiveness and to avoid deadlocks, the following guidelines must be followed when registering callbacks:

  • 콜백 메서드는 동기적으로 호출되어 콜백이 반환될 때까지 Cancel에 대한 호출이 반환되지 않으므로 콜백 메서드는 빨라야 합니다.The callback method should be fast because it is called synchronously and therefore the call to Cancel does not return until the callback returns.

  • 콜백이 실행되는 동안 Dispose를 호출하고 콜백이 대기하도록 잠금을 유지하면 프로그램에서 교착 상태가 발생할 수 있습니다.If you call Dispose while the callback is running, and you hold a lock that the callback is waiting on, your program can deadlock. Dispose가 반환되고 나서 콜백에 필요한 리소스를 해제할 수 있습니다.After Dispose returns, you can free any resources required by the callback.

  • 콜백은 한 콜백에서 수동 스레드 또는 SynchronizationContext 사용을 수행하면 안 됩니다.Callbacks should not perform any manual thread or SynchronizationContext usage in a callback. 콜백이 특정 스레드에서 실행되어야 하면 대상 syncContext가 활성 SynchronizationContext.Current가 되도록 지정할 수 있는 System.Threading.CancellationTokenRegistration 생성자를 사용합니다.If a callback must run on a particular thread, use the System.Threading.CancellationTokenRegistration constructor that enables you to specify that the target syncContext is the active SynchronizationContext.Current. 콜백에서 수동 스레딩을 수행하면 교착 상태가 발생할 수 있습니다.Performing manual threading in a callback can cause deadlock.

자세한 예제는 방법: 취소 요청에 대한 콜백 등록을 참조하세요.For a more complete example, see How to: Register Callbacks for Cancellation Requests.

대기 핸들을 사용하여 수신 대기Listening by Using a Wait Handle

취소할 수 있는 작업이 System.Threading.ManualResetEvent 또는 System.Threading.Semaphore와 같은 동기화 기본 형식에서 대기하는 동안 차단되면 CancellationToken.WaitHandle 속성을 사용하여 작업이 이벤트 및 취소 요청에서 대기하도록 할 수 있습니다.When a cancelable operation can block while it waits on a synchronization primitive such as a System.Threading.ManualResetEvent or System.Threading.Semaphore, you can use the CancellationToken.WaitHandle property to enable the operation to wait on both the event and the cancellation request. 취소 토큰의 대기 핸들은 취소 요청에 대한 응답으로 신호가 전송되고 메서드는 WaitAny 메서드의 반환 값을 사용하여 신호를 전송한 취소 토큰이었는지를 판별할 수 있습니다.The wait handle of the cancellation token will become signaled in response to a cancellation request, and the method can use the return value of the WaitAny method to determine whether it was the cancellation token that signaled. 그리고 나서 작업은 적절하게 종료되거나 OperationCanceledException을 throw합니다.The operation can then just exit, or throw a OperationCanceledException, as appropriate.

// Wait on the event if it is not signaled.
int eventThatSignaledIndex =
       WaitHandle.WaitAny(new WaitHandle[] { mre, token.WaitHandle },
                          new TimeSpan(0, 0, 20));
' Wait on the event if it is not signaled.
Dim waitHandles() As WaitHandle = { mre, token.WaitHandle }
Dim eventThatSignaledIndex =
    WaitHandle.WaitAny(waitHandles, _
                       New TimeSpan(0, 0, 20))

.NET Framework 4를 대상으로 지정한 새 코드에서 System.Threading.ManualResetEventSlimSystem.Threading.SemaphoreSlim는 둘 다 Wait 메서드에서 새 취소 프레임워크를 지원합니다.In new code that targets the .NET Framework 4, System.Threading.ManualResetEventSlim and System.Threading.SemaphoreSlim both support the new cancellation framework in their Wait methods. CancellationToken을 메서드에 전달하고 취소가 요청될 대 이벤트가 활성화되어 OperationCanceledException을 throw합니다.You can pass the CancellationToken to the method, and when the cancellation is requested, the event wakes up and throws an OperationCanceledException.

try
{
    // mres is a ManualResetEventSlim
    mres.Wait(token);
}
catch (OperationCanceledException)
{
    // Throw immediately to be responsive. The
    // alternative is to do one more item of work,
    // and throw on next iteration, because
    // IsCancellationRequested will be true.
    Console.WriteLine("The wait operation was canceled.");
    throw;
}

Console.Write("Working...");
// Simulating work.
Thread.SpinWait(500000);
Try
   ' mres is a ManualResetEventSlim
    mres.Wait(token)
Catch e As OperationCanceledException
    ' Throw immediately to be responsive. The
    ' alternative is to do one more item of work,
    ' and throw on next iteration, because
    ' IsCancellationRequested will be true.
    Console.WriteLine("Canceled while waiting.")
    Throw
End Try

 ' Simulating work.
Console.Write("Working...")
Thread.SpinWait(500000)

자세한 예제는 방법: 대기 핸들이 있는 취소 요청 수신 대기를 참조하세요.For a more complete example, see How to: Listen for Cancellation Requests That Have Wait Handles.

동시에 여러 토큰 수신 대기Listening to Multiple Tokens Simultaneously

경우에 따라 수신기는 여러 취소 토큰을 동시에 수신 대기해야 할 수 있습니다.In some cases, a listener may have to listen to multiple cancellation tokens simultaneously. 예를 들어 취소 가능한 작업은 외부에서 메서드 매개 변수에 인수로 전달되는 토큰 이외에 내부 취소 토큰을 모니터링해야 할 수 있습니다.For example, a cancelable operation may have to monitor an internal cancellation token in addition to a token passed in externally as an argument to a method parameter. 이 작업을 하려면 다음 예제와 같이 토큰 두 개 이상을 토큰 하나로 결합할 수 있는 연결된 토큰 소스를 만듭니다.To accomplish this, create a linked token source that can join two or more tokens into one token, as shown in the following example.

public void DoWork(CancellationToken externalToken)
{
   // Create a new token that combines the internal and external tokens.
   this.internalToken = internalTokenSource.Token;
   this.externalToken = externalToken;

   using (CancellationTokenSource linkedCts =
           CancellationTokenSource.CreateLinkedTokenSource(internalToken, externalToken))
   {
       try {
           DoWorkInternal(linkedCts.Token);
       }
       catch (OperationCanceledException) {
           if (internalToken.IsCancellationRequested) {
               Console.WriteLine("Operation timed out.");
           }
           else if (externalToken.IsCancellationRequested) {
               Console.WriteLine("Cancelling per user request.");
               externalToken.ThrowIfCancellationRequested();
           }
       }
   }
}
Public Sub DoWork(ByVal externalToken As CancellationToken)
   ' Create a new token that combines the internal and external tokens.
   Dim internalToken As CancellationToken = internalTokenSource.Token
   Dim linkedCts As CancellationTokenSource =
   CancellationTokenSource.CreateLinkedTokenSource(internalToken, externalToken)
   Using (linkedCts)
      Try
         DoWorkInternal(linkedCts.Token)
      Catch e As OperationCanceledException
         If e.CancellationToken = internalToken Then
            Console.WriteLine("Operation timed out.")
         ElseIf e.CancellationToken = externalToken Then
            Console.WriteLine("Canceled by external token.")
            externalToken.ThrowIfCancellationRequested()
         End If
      End Try
   End Using
End Sub

작업을 완료했을 때 연결된 토큰 소스에서 Dispose를 호출해야 합니다.Notice that you must call Dispose on the linked token source when you are done with it. 자세한 예제는 방법: 여러 개의 취소 요청 수신 대기를 참조하세요.For a more complete example, see How to: Listen for Multiple Cancellation Requests.

라이브러리 코드와 사용자 코드 간 협력Cooperation Between Library Code and User Code

통합 취소 프레임워크를 사용하면 라이브러리 코드에서 사용자 코드를 취소하고 사용자 코드에서 협조적 방식으로 라이브러리 코드를 취소할 수 있습니다.The unified cancellation framework makes it possible for library code to cancel user code, and for user code to cancel library code in a cooperative manner. 원활한 협력은 다음 지침에 따라 양측에 의존합니다.Smooth cooperation depends on each side following these guidelines:

  • 취소 가능한 작업을 제공하는 라이브러리 코드는 사용자 코드가 취소를 요청할 수 있도록 외부 취소 토큰을 허용하는 공용 메서드도 제공해야 합니다.If library code provides cancelable operations, it should also provide public methods that accept an external cancellation token so that user code can request cancellation.

  • 라이브러리 코드가 사용자 코드를 호출하면 라이브러리 코드는 OperationCanceledException(externalToken)을 협조적 취소로 해석하고 오류 예외로 해석할 필요는 없습니다.If library code calls into user code, the library code should interpret an OperationCanceledException(externalToken) as cooperative cancellation, and not necessarily as a failure exception.

  • 사용자 대리자는 적절한 시간에 라이브러리 코드의 취소 요청에 응답해야 합니다.User-delegates should attempt to respond to cancellation requests from library code in a timely manner.

System.Threading.Tasks.TaskSystem.Linq.ParallelEnumerable은 이들 지침을 따르는 클래스의 예입니다.System.Threading.Tasks.Task and System.Linq.ParallelEnumerable are examples of classes that follow these guidelines. 자세한 내용은 작업 취소방법: PLINQ 쿼리 취소를 참조하세요.For more information, see Task Cancellation and How to: Cancel a PLINQ Query.

참고 항목See also