2014-08-29 7 views
1

인위적인 예,하지만은 비동기 방식으로 다음 내가 가진 가정 :폐기 CancellationTokenRegistrations

라고 초 콜백 몇 이후로 한, 예상대로이 작동
var cts = new CancellationTokenSource(); 
cts.CancelAfter(2000); 
cts.Token.Register(Callback); 
SomethingThatMightThrow(); 
await Task.Delay(10000, cts.Token); 

. 콜백이 await Task.Delay...에서 예외로 등록 원인이 아마도 때문이라고, 하지,이 경우

var cts = new CancellationTokenSource(); 
cts.CancelAfter(2000); 
using (cts.Token.Register(Callback)) 
{ 
    SomethingThatMightThrow(); 
    await Task.Delay(10000, cts.Token); 
} 

: 그러나, 나는 Task.Delay 후 등록을 처분하려는, 그래서 다음 수정을한다고 가정 호출되기 전에 처리됩니다.

Callback이 취소시 호출되고 등록이 항상 처리되도록하는 가장 좋은 방법은 무엇입니까?

나는 다음과 같은 생각 못했지만, 나는 그것이 얼마나 강력한 확실하지 않다 : 일반적으로 통지의 다른 종류를 사용하는 이전의 시스템과 새로운 CancellationToken 시스템 상호 운용성하는 데 사용됩니다

var cts = new CancellationTokenSource(); 
cts.CancelAfter(2000); 

var ctr = cts.Token.Register(Callback); 
try 
{ 
    SomethingThatMightThrow(); 
    await Task.Delay(10000, cts.Token); 
} 
finally 
{ 
    if (!cts.Token.IsCancellationRequested) 
     ctr.Dispose(); 
} 
+1

/은'Callback' 호출 할 것으로 예상하거나 더 이상 콜백을 원하는 것이 그 후에 코드 내 어떤 지점이있는 경우 CancelAfter 시간이 지난 경우에도 호출 할 수 있습니다. 콜백이 호출되기를 원한다면 (나머지 코드가 완료되었다하더라도),'Callback'에'CancellationTokenRegistration'을 처분하십시오. –

+1

관련 : http://stackoverflow.com/questions/21367695/why- 존재하지 않는 이유가 무엇인가요? –

+0

@MattSmith -'Callback'은'SomethingThatMightThrow(); 중에 취소가 요청 된 경우에만 호출되기를 원했습니다. 작업을 기다리고 있습니다. 지연 (10000, cts.Token); 차단. – Duncan

답변

2

CancellationToken.Register 취소를 위해. 범용 "취소 콜백"으로 사용하기위한 것이 아닙니다.

당신이 작업이 취소 될 때 어떤 방법으로 응답 할 경우, 당신은 단지 적절한 예외를 잡을 :

using (var cts = new CancellationTokenSource()) 
{ 
    cts.CancelAfter(2000); 
    SomethingThatMightThrow(); 
    try 
    { 
    await Task.Delay(10000, cts.Token); 
    } 
    catch (OperationCanceledException) 
    { 
    Callback(); 
    } 
} 
+0

감사합니다. 도움이됩니다. 그러나이 접근법에 대한 나의 관심은 내가 지금 try 블록에서 OperationCanceledException을 적시에 던지기를 기다리고있는 메소드에 의존하고 있다는 것이다. ('Task.Delay'는 멋지게 동작 합니다만, 실제 코드에서는 뭔가 다른 것을 기다리고있을 것입니다.) - 내 생각은 토큰에 콜백을 등록함으로써 대신에 곧 호출 될 것이라고 보장 할 것입니다. 취소 요청. – Duncan

+0

@Duncan : 메소드가'CancellationToken'을 취하면'OperationCanceledException'을 던져야합니다. –

+0

메소드가 예외를 throw하지 않을 수도 있습니다. 원하는만큼 빨리 던지지 않을 수도 있습니다. Azure SDK 비동기 메소드 중 일부가 예를 들어, 토큰에서 신호가 취소되는 것에 응답하는 데 꽤 오래 걸리는 것으로 나타났습니다 ... – Duncan

0

그 방법은 같이 예외를 발생하지 않을 수 있습니다 너무 많은 아니라 그 내가 원했던대로 빨리 던지지 않을 수도 있습니다. 나는 푸른 SDK 비동기 방법 중 일부 나타났습니다 예를 들어, 당신이 의견에 따라, 토큰

에 신호되고 취소 할 응답에 꽤 시간이 걸릴 수 있습니다, 당신은 당신의 자신의 타이머를 만들 수 있습니다 표준에 따라 메소드가 "실행하는 데 너무 오래 걸리는 경우"를 명시 적으로 지정합니다. 이를 위해 당신은 Task.WhenAny를 사용할 수 있습니다

당신이 * 항상 * 것인지 명확하지 않다
using (var cts = new CancellationTokenSource()) 
{ 
    try 
    { 
     var cancellationDelayTask = Task.Delay(2000, cts.Token); 
     var taskThatMightThrow = SomethingThatMightThrowAsync(cts.Token); 

     if ((await Task.WhenAny(taskThatMightThrow, cancellationDelayTask)) 
      == cancellationDelayTask) 
     { 
      // Task.Delay "timeout" finished first. 
     } 
    } 
    catch (OperationCanceledException) 
    { 
     Callback(); 
    } 
}