不检查是否已取消的 TPL 任务是否仍可取消?
Can a TPL task that doesn't check whether it's cancelled, still be cancelled?
我认为 CancellationToken/CancellationTokenSource 系统工作起来有点像 C++ volatile bool bFlagCancelled
,这意味着取消是任务自愿的,依赖于任务本身不时检查时间是否取消并抛出异常,显式或通过调用 ThrowIfCancellationRequested()
.
但是如果我在 StartNew()
之后立即调用 Cancel,任务就会停止,并且调用 Wait()
会抛出一个 TaskCanceledException
.
例如,对于此代码:
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
Task task = Task.Factory.StartNew(
() =>
{
Console.WriteLine("start sleep");
Thread.Sleep(1000);
Console.WriteLine("sleep ended");
}
, token);
// Thread.Sleep(1);
source.Cancel();
Console.WriteLine("start wait");
task.Wait();
Console.WriteLine("wait ended");
我得到这个输出:
start wait
Exception: System.AggregateException: One or more errors occurred. ---> System.Threading.Tasks.TaskCanceledException: A task was canceled.
但是如果我取消注释 // Thread.Sleep(1);
,那么行为就会改变,我会得到这个输出:
start sleep
start wait
sleep ended
wait ended
现在我想也许这是因为尚未调用 task.Start()
,但据我了解,StartNew()
在返回之前调用了 task.Start()
- 这就是它没有调用的原因有同步成本,建议不要创建 new Task
并自己调用 task.Start()
。
那么这意味着在某些情况下,任务会自发取消,即使没有检查取消标记。这是发生这种情况的唯一情况,还是有更多情况发生这种情况?
Task.Factory.StartNew
在返回之前调度任务,但并不意味着任务真正开始执行。所以还有取消任务的空间,如果 TaskScheduler
接受它(在内部,调用 TaskScheduler.TryDequeue
方法。如果 returns 为真,任务可以被标记为已取消)。 =14=]
我认为 CancellationToken/CancellationTokenSource 系统工作起来有点像 C++ volatile bool bFlagCancelled
,这意味着取消是任务自愿的,依赖于任务本身不时检查时间是否取消并抛出异常,显式或通过调用 ThrowIfCancellationRequested()
.
但是如果我在 StartNew()
之后立即调用 Cancel,任务就会停止,并且调用 Wait()
会抛出一个 TaskCanceledException
.
例如,对于此代码:
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
Task task = Task.Factory.StartNew(
() =>
{
Console.WriteLine("start sleep");
Thread.Sleep(1000);
Console.WriteLine("sleep ended");
}
, token);
// Thread.Sleep(1);
source.Cancel();
Console.WriteLine("start wait");
task.Wait();
Console.WriteLine("wait ended");
我得到这个输出:
start wait Exception: System.AggregateException: One or more errors occurred. ---> System.Threading.Tasks.TaskCanceledException: A task was canceled.
但是如果我取消注释 // Thread.Sleep(1);
,那么行为就会改变,我会得到这个输出:
start sleep start wait sleep ended wait ended
现在我想也许这是因为尚未调用 task.Start()
,但据我了解,StartNew()
在返回之前调用了 task.Start()
- 这就是它没有调用的原因有同步成本,建议不要创建 new Task
并自己调用 task.Start()
。
那么这意味着在某些情况下,任务会自发取消,即使没有检查取消标记。这是发生这种情况的唯一情况,还是有更多情况发生这种情况?
Task.Factory.StartNew
在返回之前调度任务,但并不意味着任务真正开始执行。所以还有取消任务的空间,如果 TaskScheduler
接受它(在内部,调用 TaskScheduler.TryDequeue
方法。如果 returns 为真,任务可以被标记为已取消)。 =14=]