2016-04-04 13 views
0

キャンセルトークンでTask.Runを使用するコードがあります。Task.RunにCancellationTokenを使用する

はここに私のコードです:私はTaskAction()TaskCancel()を呼び出す場合

public class TaskObject 
{ 
    CancellationTokenSource _source = new CancellationTokenSource(); 
    public async Task TaskAction() 
    { 
     var task = Task.Run(async delegate 
     { 
      await TaskRun(); 
     }, _source.Token); 

     //TaskCancel(); 

     try 
     { 
      task.Wait(); 
     } 
     catch (Exception ex) 
     { 

     } 
    } 
    public async Task TaskRun() 
    { 
     if (_source.IsCancellationRequested) 
     { 
      _source.Token.ThrowIfCancellationRequested(); 
     } 

     SpeechSynthesizer _speechSynthesizer = new SpeechSynthesizer(); 
     _speechSynthesizer.SpeakAsync("This is a test prompt"); 
    } 
    public void TaskCancel() 
    { 
     _source.Cancel(); 
    } 
} 

、タスクキャンセル例外がキャッチされます。

オブジェクトの外側からTaskCancel()を呼び出すと、キャンセルされた例外は捕捉されません。ここで

はキャンセル例外がキャッチされていない場所を実証するためのいくつかのコードです:

taskObject = new TaskObject(); 
await taskObject.TaskAction(); 
taskObject.TaskCancel(); 

キャンセル例外がキャッチされたように、私は対象外からTaskCancel()を呼び出すことができますどのように?

答えて

4

キャンセルは協調する必要があります。 Task.Runは、スケジュールされたデリゲートがどのような副作用を持っているかを意識していないため、がCancellationTokenをチェックし、OCEをスローする唯一の論理的な安全点はです。の前に非同期操作が開始されます - そのポイントの後で、トークンをチェックするのはユーザーコードまでです。

問題は、あなたのユーザコードが、CancellationTokenを受け入れるオーバーロードを持たない、SpeechSynthesizer.SpeakAsyncを待っていることです。

SpeechSynthesizerは、しかし、あなたはそのようにそれをプラグインすることができSpeakAsyncCancelAll方法を、持っているん:

public async Task TaskRun(CancellationToken ct) 
{ 
    ct.ThrowIfCancellationRequested(); 

    SpeechSynthesizer _speechSynthesizer = new SpeechSynthesizer(); 

    using (ct.Register(() => _speechSynthesizer.SpeakAsyncCancelAll())) { 
     await _speechSynthesizer.SpeakAsync("This is a test prompt"); 
    } 
} 

私は、これは操作がキャンセルされたことを示す例外を生成するかどうかを伝えることはできません - あなたをあなた自身のために試してみる必要があります。

+0

SpeechSynthesizerを無視して、Task.Runが開始されたときに、機能の開始時に取り消し要求が検出されない限り、取り消し要求を検出する方法はありません。 – user3736648

+0

@ user3736648、あなたは正しいアイデアを持っているようですが、表現には若干の磨きが必要です(最初の段落を参照)。簡単に言えば、 'Task.Run'はスレッドプール上でデリゲートを実行する前に' CancellationToken'を一度チェックします。デリゲートの呼び出しが進行すると、 'Task.Run'は何もできません。 –

+0

ありがとうございます。 Task.Run以外に、いつでも取り消すことができるスレッドを作成する正しい方法がありますか? – user3736648

関連する問題