2019. 11. 29. 18:24 개발언어/C#
CancellationTokenSource 과 CancellationToken
출처 : MSDN : https://docs.microsoft.com/ko-kr/dotnet/standard/threading/cancellation-in-managed-threads
우리가 비동기 함수를 호출할 때 가령 socket의 accept를 비동기로 호출한 후
서버 가동을 중지할 때 해당 Accept를 중지하는 경우 등등 해당 비동기 함수에 대하여
작업을 취소해야하는 경우가 있을 수 있다.
이런 경우 해당 함수에 대하여 직접적인 접근을 할 수도 있겠지만
단순히 중지를 알림으로써 해결할 수도 있을 것이다.
이와 관련하여 사용할 수 있는것이 CancellationTokenSource와 CancellationToken이다.
이해한 바에 따르면 우선 Token의 경우 구조체이기 때문에 값복사가 이루어진다.
이러한 토큰은 TokenSource의 인스턴스가 제공하는 CancellationTokenSource.Token의 반환값을 사용하며,
이 token을 각각의 "취소요청을 수신할 스레드"에 전달한다.
물론 위의 스레드, 작업(Task)의 경우 token이 최소된 경우 처리할 로직을 구현해야한다.
더불어 만약 TokenSource가 Token외 별도의 리소스를 지닌 상태라면
해당 리소스에 관한 처리도 Dispose에서 처리해줘야 한다.
MSDN에서 제공한 소스코드 예제를 보자.
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...
위에서 보이듯이 TokenSource인 cst가 cancel함수를 호출한 경우
DoSomeWork의 인자로 들어간 token의 IsCancellationRequest가 바뀐다.
이 때 token이 IsCancellationRequested가 한번 true로 변경될 시 다시 false로 바꿀 수 없다.
또 다른 활용법으로는 취소 요청이 호출된 순간에 처리할 작업을 지정하는것도 가능하다.
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
위 코드에서 보이듯이 해당 token에 Register 함수를 통해 token에 취소 요청이 올 경우 처리할 작업을 등록할 수 있다.
이 외에 Exception 을 활용한 방법도 존재하며 이방법에 대해서는 아래의 링크를 참고하면 된다.
https://docs.microsoft.com/ko-kr/dotnet/standard/parallel-programming/task-cancellation
'개발언어 > C#' 카테고리의 다른 글
Thread와 Task (0) | 2021.06.20 |
---|---|
ThreadStatic 과 ThreadLocal (0) | 2019.11.28 |
알아두면 어쩌다 쓸것같은 Attribute들-1 (0) | 2019.09.05 |
async, await란 (0) | 2019.08.11 |