1

私はCancellationToken/CancellationTokenSourceシステムがC++ volatile bool bFlagCancelledのような働きをしていると考えました。これは、キャンセルは自発的にタスクの部分で行われ、タスク自体が随時チェックされてキャンセルされ、例外がスローされるかどうかを確認します明示的に、またはThrowIfCancellationRequested()を呼び出してキャンセルされていないかどうかをチェックしないTPLタスクは引き続きキャンセルできますか?

StartNew()の直後にキャンセルを呼び出すと、タスクが停止し、を呼び出すと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()を作成することをお勧めします。

この場合、キャンセルトークンを確認しなくても、タスクが自動的にキャンセルされることがあります。これが起こる唯一の状況ですか、これが起こるより多くのシナリオがありますか?

答えて

1

Task.Factory.StartNewは、タスクが実際に実行を開始したことを意味するものではありません。したがって、TaskSchedulerがそれを受け入れる場合は、タスクをキャンセルする余地が残っています(内部では、TaskScheduler.TryDequeueメソッドが呼び出されます)。タスクは、trueを返すとキャンセルされたとマークすることができます。

+0

答えをありがとう。これが起こる可能性がある他の状況はありますか、これは唯一のものですか? – sashoalm

+1

@sashoalmタスクがまだ「実行中」に遷移していないときはいつでも。たとえば、タスクで 'ContinueWith'を呼び出してこのタスクをキャンセルすると、継続もキャンセルされます –

+0

もう一度ありがとうございます。私はちょうどhttp://stackoverflow.com/a/10444108/492336を見つけました。ここで、 'StartNew'に' token'を渡すことは、特にこの動作を有効にすることであり、本当に 'StartNew()'にトークンを渡さないことが説明されています。 '// Sleep(1)'のコメントを解除するのと同じ効果があります。 – sashoalm

関連する問題