2012-02-10 15 views
1

最近、重いバックグラウンドタスクを実行するためのツールキットとしてTPLを採用しました。TPLでUIスレッドに `Disposable`オブジェクトを安全に渡す

これらのタスクは、通常、IDisposableを実装する単一のオブジェクトを生成します。これは内部的にいくつかのOSハンドルがあるためです。

バックグラウンドスレッドによって生成されたオブジェクトは、ハンドオーバがアプリケーションシャットダウンと同時に発生した場合でも、常に適切に処理されます。

private void RunOnUiThread(Object data, Action<Object> action) 
    { 
     var t = Task.Factory.StartNew(action, data, CancellationToken.None, TaskCreationOptions.None, _uiThreadScheduler); 
     t.ContinueWith(delegate(Task task) 
      { 
       if (!task.IsCompleted) 
       { 
        DisposableObject.DisposeObject(task.AsyncState); 
       } 
      });    
    } 

背景がTask UIスレッドにその結果を渡すためにRunOnUiThreadを呼び出します。

は、いくつかの思考の後、私はこれを書きました。 tタスクはUIスレッドでスケジュールされ、 dataの所有権が渡されます。 tが実行できなかった場合、uiスレッドのメッセージポンプがシャットダウンされたため継続が実行され、タスクは失敗し、オブジェクトを自分で処分しました。 DisposeObject()は、オブジェクトが実際にIDisposableで、nullでない場合、それを廃棄する前にチェックするヘルパーです。

悲しいことに、うまくいきません。バックグラウンドタスクtの作成後にアプリケーションを閉じると、継続は実行されません。

私は以前この問題を解決しました。当時、私はスレッドスレッドとWPFディスパッチャーを使ってメッセージをUIスレッドに投稿していました。それはあまりにもかわいいものではありませんでしたが、結局はそれは働きました私はTPLがこのシナリオでより良いと思っていました。 IDisposableを実装している場合は、残っているAsyncStateオブジェクトをすべて破棄する必要があることをTPLに教えることができればさらに良いでしょう。

したがって、コードは主に問題を説明することです。私は、バックグラウンドタスクから使い捨てオブジェクトをUIスレッドに安全にハンドオーバできる任意のソリューションについて学びたいと思います。できるだけコードを少なくすることをお勧めします。

+1

あり、単に何のポイントを。オブジェクトが必要以上に長くならないようにオブジェクトを破棄します。プロセスのシャットダウン後も何も残っていません。 Windowsは開いたままのハンドルをクリーンアップします。 AppDomainは、それ自体は必要ないでしょうが、シャットダウンする前にファイナライザを実行します。未完成のタスクがまだ残っている間にアプリをシャットダウンできるようにするのが良い方法があります。 –

答えて

0

RXライブラリをご覧ください。これにより、あなたが望むことをすることができます。 MSDNから

+0

実際に私はそれを見ました。そこに 'IDisposable'オブジェクトの特別な処理について知っていますか? –

+0

いいえ、IObservableは常にOnErrorまたはOnCompletedのいずれかを呼び出しますので、そこに配置することができます。 – Chriseyre2000

+0

私は参照してください....問題は、これがOnErrorのためのプロデューサの例外ではないことです、私はそれを理解しています。しかし、私はとにかくそれを試してみません...誰かがより良い提案を思い付かない限り。 –

0

:タスク3つの 最終のいずれかの状態にあるときに

IsCompletedはtrueを返します。つまりRanToCompletionFaulted、またはCanceled

、あなたはDisposableObject.DisposeObject決して上記の条件の1つが実行された後に継続が予定されているため、呼び出すことができます。私が何であったか、あなたが行うためのものと考えている:

t.ContinueWith(t => DisposableObject.DisposeObject(task.AsyncState), 
       TaskContinuationOptions.NotOnRanToCompletion) 

は、私はあなたが欲しい何かのために継続を使用していないだろうしかし

(ところであなたは、単にAsyncStateプロパティを使用するのではなく、変数dataをキャプチャしている可能性があり)常に確実に起こるようにしてください。私はtry-finallyブロックは、ここでより多くのフィッティングになると信じて:

private void RunOnUiThread2(Object data, Action<Object> action) 
{ 
    var t = Task.Factory.StartNew(() => 
    { 
     try 
     { 
      action(data); 
     } 
     finally 
     { 
      DisposableObject.DisposeObject(task.AsyncState); 
      //Or use a new *foreground* thread if the disposing is heavy 
     } 
    }, CancellationToken.None, TaskCreationOptions.None, _uiThreadScheduler); 
} 
関連する問題