14

GUI スレッドのロックを回避するために、別のスレッドで実行する必要がある時間のかかるタスクがあります。このタスクが進行すると、特定の GUI コントロールが更新されます。

問題は、タスクが終了する前にユーザーが GUI の別の部分に移動する可能性があることです。その場合、次のことを行う必要があります。

  1. 進行中のタスクをキャンセルします (アクティブな場合)
  2. キャンセルが完了するまで待ちます。時間のかかるタスクの目的は特定のコントロールを更新することであるため、これは非常に重要です。複数のスレッドが同時にそれを実行しようとすると、事態が混乱する可能性があります。
  3. タスクを最初から起動する

具体的な例として、フォームに 2 つの部分があるとします。1 つはディレクトリ ツリーをナビゲートする部分で、もう 1 つはサムネイルを表示する部分です。ユーザーが別のディレクトリに移動すると、サムネイルを更新する必要があります。

BackgroundWorker最初は aと anを使ってキャンセル待ちをしようと思ったのですAutoResetEventが、キャンセル時に行き詰ってしまったので何かを間違えたのでしょう。次に、BGW およびより原始的なメカニズムを置き換えることになっている TPL について読みました。

これは TPL を使用して簡単に実行できますか?

4

1 に答える 1

28

注意すべき点がいくつかあります。

  • CancellationTokenからを得ることができますCancellationTokenSource

  • タスクのキャンセルは協調的なアクションです。タスクがプロパティを定期的にチェックしない場合、タスクCancellationToken.IsCancellationRequestedをキャンセルしようとしても、タスクはすぐに消えてしまいます。

それらのことは言った、ここに一般的な考えがあります:

void Main()
{
    var tokenSource = new CancellationTokenSource();
    var myTask = Task.Factory
        .StartNew(() => DoWork(tokenSource.Token), tokenSource.Token);

    Thread.Sleep(1000);

    // ok, let's cancel it (well, let's "request it be cancelled")
    tokenSource.Cancel();

    // wait for the task to "finish"
    myTask.Wait();
}

public void DoWork(CancellationToken token)
{
    while(!token.IsCancellationRequested)
    {
        // Do useful stuff here
        Console.WriteLine("Working!");
        Thread.Sleep(100);
    }
}
于 2013-02-14T21:37:13.163 に答える