2016-05-01 6 views
0

私は1つの方法でUploaderクラスを持っている - Uploadキャンセル非同期アップロードタスク

public static int Upload(string endpoint,object objectToBeUploaded) 
    { 
     Source.Token.ThrowIfCancellationRequested(); 
     var repos = new UploadRepository(endpoint); 
     return repos.Upload(objectToBeUploaded); 
    } 

Sourceは、プロジェクトで利用できる静的CancellationTokenSourceです。

また、アップロードする必要があるエンドポイントのリストがあります。object

Formのコードは、(それがWinFormsを使用して、非常に小さなプロジェクトだ)次のようになります。

private async Task UploadObjectAsync(
      string endpoint, 
      object objectToBeUploaded) 
    { 
     try 
     { 
      int elementId = await Task.Factory.StartNew(
         () => Uploader.Upload(endpoint,objectToBeUploaded)); 
      //do something with the returned value.. 
     } 
     catch(OperationCanceledEception ex) 
     { 
      //handle the exception.. 
     } 
    } 

そして私はので、私は後でそれを使用することができ、このようなbtnUpload.Clickハンドラを設定します。

this.btnUpload.Click += async (s, e) => 
{ 
    foreach(var endpoint in endpoints) 
    { 
     await UploadObjectASsync(endpoint,someObject); 
    } 
} 

問題は、すべてのエンドポイントにアップロードを開始するとき(取得方法とは無関係)、を使用してアップロードプロセスをキャンセルすることにしたとき、最初のUploadObjectAsyncUploadの方法が既に渡されているため、 Source.Token.ThrowIfCancellationRequested();のチェックが行われてから経過しています。残りのタスクは正常にキャンセルされ、正常に処理されます。

最初のUploadObjectAsyncTaskもキャンセルされるように、このコードを再構成する方法を教えてください。

私はUploadメソッドのrepos.Upload(objectToBeUploaded)というアップロードプロセス自体(サービス参照)のソースコードにもアクセスできません。

答えて

1

あなたはUploadRepository.UploadをCancellationTokenにする必要があります。 特にI/O操作を実行しているとき。それがasync/awaitが実際に支払いをするときです。

これはまた: Uploadメソッドがタスクを既に返すので、それを取り除くのに役立ちます。タスクをスピンオフする必要はありません。

あなたの現在の設定では、タスクが開始されるのに十分な時間が与えられており(ThrowIfCancellationRequestedを通過する)、アップロードをキャンセルすることはできません。 30秒かかる場合でも。問題は、あなたはそれがどんな自体を終了CancellationTokenの状態をチェックしない限り、Upload機能の内部で起こるプロセスを停止することができないということですTask.Run

1

実際にできることはありません。 Uploadメソッドはトークンを取得しません。最初のタスクは、キャンセルボタンを押した時点で既にキャンセルチェックに合格しています。あなたは、取り消したコールがあった場合に投げに先立って10秒の睡眠を加えることによって、キャンセルがタイミングの問題であることを自分自身に証明することができます。すべてのタスクがキャンセルされます。

0

また、あなたは、に興味があるかもしれません。

だから何あなたができることは、このような何か行うことによって実行されるスレッド中止することです:あなたはトークンは、トークンがキャンセルされた場合には、その関数を呼び出すことが原因Source.Token.Register(delegate)機能を使用して

int elementId = await Task.Factory.StartNew(() => 
{ 
    try 
    { 
    using (Source.Token.Register(Thread.CurrentThread.Interrupt)) 
    { 
     return Uploader.Upload(endpoint, objectToBeUploaded)); 
    } 
    } 
    catch (ThreadInterruptedException ex) 
    { 
    throw new OperationCanceledEception(ex) 
    } 
}, Source.Token); 

を。この方法では、現在実行中のスレッドがアップロードされ、すぐに例外をスローする必要があります。

このメソッドは、スレッドがその状態にある場合にのみ例外が発生するため、スレッドがWaitSleepJoin -Stateを時々入力する場合にのみ機能します。 Thread.Interrupt関数のドキュメントを見てください。

代わりにThread.AbortThreadAbortedExceptionを使用することです。いずれにしてもスレッドは強制終了しますが、スレッドが保持するロックは適切に解放されないため、サービスの内部状態が破損する可能性があります。したがって、この方法を使用する際は非常に注意してください。

+0

実際にはアドバイスされていません。 –

+0

ええと...スレッドを中断するのは比較的安全です。 – Nitram

+0

うん。アップロードコードは変更する必要があります。それが彼の支配から外れていれば、これは行く方法でしょう。 –