1

私たちは最近、重いバックグラウンド タスクを実行するためのツールキットとして TPL を採用しました。

これらのタスクは通常、 を実装する単一のオブジェクトを生成します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で呼び出しRunOnUiThreadて、その結果を UI スレッドに渡します。タスクtは UI スレッドでスケジュールされ、data渡されたものの所有権を取得しtます。UI スレッドのメッセージ ポンプがシャットダウンされたために実行できなかった場合、継続が実行されると予想していましたが、タスクに失敗し、自分でオブジェクトを破棄します。DisposeObject()オブジェクトを破棄する前に、オブジェクトが実際に IDisposable であり、null でないかどうかをチェックするヘルパーです。

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

以前にこの問題を解決しました。当時、私は Threadpool と WPF Dispatcher を使用して UI スレッドにメッセージを投稿していました。あまりきれいではありませんでしたが、最終的にはうまくいきました。このシナリオでは TPL の方が優れていることを期待していました。IDisposable を実装している場合は、残りの AsyncState オブジェクトをすべて破棄する必要があることを TPL に教えることができれば、さらに良いでしょう。

したがって、コードは主に問題を説明するためのものです。Disposable オブジェクトをバックグラウンド タスクから UI スレッドに安全に引き渡すことができるソリューション、できればコードをできるだけ少なくするソリューションについて学びたいと考えています。

4

3 に答える 3

1

プロセスが閉じると、そのカーネルハンドルはすべて自動的に閉じられます。これについて心配する必要はありません:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms686722(v=vs.85).aspx

于 2012-02-11T20:50:53.323 に答える
0

RXライブラリを見てください。これにより、やりたいことができるようになるかもしれません。

于 2012-02-10T22:43:20.397 に答える
0

MSDNから:

IsCompletedTask がRanToCompletionFaulted、またはCanceled

DisposableObject.DisposeObjectつまり、上記の条件のいずれかが発生した後に継続が常にスケジュールされるため、 yourが呼び出されることはありません。私はあなたがするつもりだったと信じています:

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

data(ところで、プロパティを使用するのではなく、単に変数をキャプチャすることもできAsyncStateます)

ただし、常に発生するようにしたいものには継続を使用しません。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);
}
于 2012-02-11T18:55:54.340 に答える