CancellationTokenSource 在给定超时后不会取消任务
CancellationTokenSource does not cancel task after given timeout
我正在学习 TAP,我喜欢使用单元测试探索 TPL 数据流。我无法理解以下内容:
var cts = new CancellationTokenSource(500);
var tcs = new TaskCompletionSource<bool>(cts.Token);
var agent = new ActionBlock<FakeMessage>( async evt =>
{
await Task.Delay(5000);
tcs.SetResult(true);
});
agent.Post(new FakeMessage());
try
{
var result = await tcs.Task;
Assert.Fail();
}
catch (OperationCanceledException ex)
{
Assert.IsTrue(true);
}
catch (Exception e)
{
Assert.Fail();
}
我原以为它会提高第一行定义的超时并赶上 OperationCanceledException
,但我总是以 Assert.Fail
跟随 await tcs.Task
结束。有人能解释一下我的假设有什么问题吗?
TaskCompletionSource
不接受 CancellationToken
.
它确实接受一个 Object
状态,你可以在技术上将一个 CancellationToken
传递给它,但它不会做任何事情,尤其是不取消 TaskCompletionSource
.
如果你想取消 TaskCompletionSource
你可以用一个简单的超时来做到这一点:
Task.Delay(500).ContinueWith(t => tcs.SetCancelled());
您还可以创建一个 TaskCompletionSource
接受 CancellationToken
并在 TaskCompletionSource
被取消时自行取消:
class TaskCompletionSourceWithCancellation<T> : TaskCompletionSource<T>
{
public CancellationToken CancellationToken { get; }
public TaskCompletionSourceWithCancellation(CancellationToken cancellationToken)
{
CancellationToken = cancellationToken;
var cancellationTokenRegistration =
cancellationToken.Register(
_ => ((TaskCompletionSourceWithCancellation<TResult>)_).TrySetCanceled(),
this);
Task.ContinueWith(_ => cancellationTokenRegistration.Dispose());
}
}
我正在学习 TAP,我喜欢使用单元测试探索 TPL 数据流。我无法理解以下内容:
var cts = new CancellationTokenSource(500);
var tcs = new TaskCompletionSource<bool>(cts.Token);
var agent = new ActionBlock<FakeMessage>( async evt =>
{
await Task.Delay(5000);
tcs.SetResult(true);
});
agent.Post(new FakeMessage());
try
{
var result = await tcs.Task;
Assert.Fail();
}
catch (OperationCanceledException ex)
{
Assert.IsTrue(true);
}
catch (Exception e)
{
Assert.Fail();
}
我原以为它会提高第一行定义的超时并赶上 OperationCanceledException
,但我总是以 Assert.Fail
跟随 await tcs.Task
结束。有人能解释一下我的假设有什么问题吗?
TaskCompletionSource
不接受 CancellationToken
.
它确实接受一个 Object
状态,你可以在技术上将一个 CancellationToken
传递给它,但它不会做任何事情,尤其是不取消 TaskCompletionSource
.
如果你想取消 TaskCompletionSource
你可以用一个简单的超时来做到这一点:
Task.Delay(500).ContinueWith(t => tcs.SetCancelled());
您还可以创建一个 TaskCompletionSource
接受 CancellationToken
并在 TaskCompletionSource
被取消时自行取消:
class TaskCompletionSourceWithCancellation<T> : TaskCompletionSource<T>
{
public CancellationToken CancellationToken { get; }
public TaskCompletionSourceWithCancellation(CancellationToken cancellationToken)
{
CancellationToken = cancellationToken;
var cancellationTokenRegistration =
cancellationToken.Register(
_ => ((TaskCompletionSourceWithCancellation<TResult>)_).TrySetCanceled(),
this);
Task.ContinueWith(_ => cancellationTokenRegistration.Dispose());
}
}