我对取消令牌源产生了疑问,下面的代码中我正在使用它:
void Process()
{
//for the sake of simplicity I am taking 1, in original implementation it is more than 1
var cancellationToken = _cancellationTokenSource.Token;
Task[] tArray = new Task[1];
tArray[0] = Task.Factory.StartNew(() =>
{
cancellationToken.ThrowIfCancellationRequested();
//do some work here
MainTaskRoutine();
}, cancellationToken);
try
{
Task.WaitAll(tArray);
}
catch (Exception ex)
{
//do error handling here
}
}
void MainTaskRoutine()
{
//for the sake of simplicity I am taking 1, in original implementation it is more than 1
//this method shows that a nested task is created
var cancellationToken = _cancellationTokenSource.Token;
Task[] tArray = new Task[1];
tArray[0] = Task.Factory.StartNew(() =>
{
cancellationToken.ThrowIfCancellationRequested();
//do some work here
}, cancellationToken);
try
{
Task.WaitAll(tArray);
}
catch (Exception ex)
{
//do error handling here
}
}
编辑: 进一步解释
最终目标是: 当用户取消操作时,所有正在进行的立即挂起任务(包括子任务或孙子任务)都应该被取消。
场景: 根据上述代码: 1. 首先检查用户是否要求取消 2. 如果用户没有要求取消,则继续执行任务 (请参阅Process方法)。 样本代码仅显示一个任务,但实际上可能有三个或更多
假设 CPU 在处理 Task1 的同时,其他任务仍在任务队列中等待某个 CPU 来执行它们。 用户请求取消:Process 方法中的 Task 2,3 立即取消,但 Task 1 将继续工作,因为它已经在处理中。
Task 1 中调用了 MainTaskRoutine 方法,该方法又创建了更多的任务。
在 MainTaskRoutine 函数中,我写道:cancellationToken.ThrowIfCancellationRequested();
所以问题是: 这种使用 CancellationTokenSource 的方式是否正确,因为它依赖于 Task.WaitAll()?
Task.Run
将展开嵌套任务,因此从Task.Run
返回的任务实际上是由MainTaskRoutine
返回的任务。还要注意使用的TaskContinuationOptions.ExecuteSynchronously
,以确保在触发WhenAll
之前执行清理代码。 - noseratio - open to workcancellationToken.ThrowIfCancellationRequested()
,任何挂起的任务都将被取消。Process
和MainTaskRoutine
本身不执行任何CPU绑定的任务,因此它们将在其所有子任务已完成(WhenAll
)后立即被取消。但是,您可以在“Process”和“MainTaskRoutine”的开头添加cancellationToken.ThrowIfCancellationRequested()
,以确保它们不会启动任何子任务。 - noseratio - open to workCancellationTokenSource.Token
传递给尽可能多的任务,前提是它们都应该在调用该CancellationTokenSource
对象上的CancellationTokenSource.Cancel
后逻辑上被取消。 - noseratio - open to work