3

私は次のコードを書きました:

CancellationTokenSource tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;

int i = 0;
Console.WriteLine("Calling from Main Thread {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);

Task t1 = new Task(() =>
{
    while (true)
    {
        try
        {
            token.ThrowIfCancellationRequested();
        }

        catch (OperationCanceledException)
        {
            Console.WriteLine("Task1 cancel detected");
            break;
        }

        Console.WriteLine("Task1: Printing: {1}", System.Threading.Thread.CurrentThread.ManagedThreadId, i++);
    }
}, token);

Task t2 = new Task(() =>
{
    while (true)
    {
        try
        {
            token.ThrowIfCancellationRequested();
        }

        catch (OperationCanceledException)
        {
            Console.WriteLine("Task2 cancel detected");
            break;
        }

        Console.WriteLine("Task2: Printing: {1}", System.Threading.Thread.CurrentThread.ManagedThreadId, i++);
    }
});

t1.Start();
t2.Start();
Thread.Sleep(100);
tokenSource.Cancel();

t1.Wait();//wait for thread to completes its execution
t2.Wait();//wait for thread to completes its execution
Console.WriteLine("Task1 Status:{0}", t1.Status);
Console.WriteLine("Task2 Status:{0}", t1.Status);

ここでタスクをキャンセルすると、ステータスにも RanToCompletion が表示されますが、両方のタスクの待機を削除すると、キャンセルされたステータスが表示されます...

タスクをキャンセルしているので、いずれにしてもキャンセルされたステータスを期待しています...

EDIT : From MSDN OperationCanceledException をスローし、キャンセルが要求されたトークンを渡します。これを行うには、ThrowIfCancellationRequested メソッドを使用することをお勧めします。この方法でキャンセルされたタスクは Canceled 状態に遷移し、呼び出し元のコードはこれを使用して、タスクがキャンセル要求に応答したことを確認できます。

Wait メソッドまたは WaitAll メソッドを使用してタスクを待機しない場合、タスクはそのステータスを単に Canceled に設定します。

4

1 に答える 1

6

OperationCanceledException をキャッチして while ループから抜けると、タスクは正常に終了し、タスクのステータスは RanToCompletion になります。

Canceled ステータスを取得するには、OperationCanceledException を再スローするか、まったくキャッチしない必要があります。

MSDNによると、タスク ステータスは次の場合にキャンセルされます。

タスクは、トークンがシグナル状態にあるときに独自の CancellationToken を使用して OperationCanceledException をスローすることによってキャンセルを確認したか、タスクの実行が開始される前にタスクの CancellationToken が既にシグナル状態になっていました。詳細については、「タスクのキャンセル」を参照してください。

ソース コードで例外を飲み込んだため、タスク ステータスは RanToCompletion になります。

待機を削除したときにステータスがキャンセルされた理由についての質問に答えるには、おそらく例外がまだキャッチされておらず、キャンセルステータスが以前にチェックされているためです。この動作は、信頼性や再現性があるとは見なされません。

于 2012-08-26T12:03:25.383 に答える