web-dev-qa-db-ja.com

C#スレッド化/非同期:UIが対話可能なときにバックグラウンドでタスクを実行する

Async/AwaitとThreadingの両方を調べた後、それを自分の状況に適用する正しい方法がまだわかりません。目的の関数を非同期に呼び出していないように見えるため、UIを試しても、ハングしたままになります。さらに、実際にはソリューションにスレッドが必要な場合があります。

私がやろうとしていること: WPFアプリケーションがあり、UIを介してプログラムとの対話を許可する操作を開始したいボタンがあります。この関数の外部で決定された条件が満たされると、関数は終了するはずです。私にはこれはかなり標準に聞こえますが、私は何かを誤解していると感じており、間違って実装しています。

私が今持っているもの:

private async void start_button_Click(object sender, RoutedEventArgs e)
{
    await StaticClass.MyFunction();
}

private void stop_button_Click(object sender, RoutedEventArgs e)
{
    StaticClass.stopFlag = true;
}

public static Task<int> myFunction()
{
    //Stuff Happens

    while(StaticClass.stopFlag == false)
        //Do Stuff

    //Stuff Happens

    return Task.FromResult(1) //I know this is bad, part of the reason I'm asking
}

私はこれに正しい方法でアプローチしているかどうかについてのガイダンスと、私が間違っていることに関する洞察を望んでいました。

18
Karoly S

あなたは間違いなくそれを間違って実装しました。 Task<int>を返していますが、すべての作業が既に完了している場合のみを返します。

おそらく、同期メソッドが必要だと思われます。

private static void MyFunction()
{
    // Loop in here
}

次に、次のようにタスクを開始します。

Task task = Task.Run((Action) MyFunction);

その後、必要に応じてそのタスクを待つことができます。指定した例では、awaitの後に何もしないので、そうすることに意味はありません。

また、CancellationTokenを使用することは、他の場所の静的フラグよりもクリーンになることにもReedに同意します。

25
Jon Skeet

あなたは誤解しました。

_public static Task<int> myFunction()
{
    //Stuff Happens

    while(StaticClass.stopFlag == false)
        //Do Stuff

    //Stuff Happens

    return Task.FromResult(1) //I know this is bad, part of the reason I'm asking
}
_

そのコードはすべて、最初のawait StaticClass.MyFunction();呼び出しで発生します。呼び出し元に制御を返すことはありません。必要なのは、ループ部分を別のスレッドに入れることです。

_public static async Task myFunction()
{
    //Stuff Happens on the original UI thread

    await Task.Run(() => //This code runs on a new thread, control is returned to the caller on the UI thread.
    {
        while(StaticClass.stopFlag == false)
            //Do Stuff
    });

    //Stuff Happens on the original UI thread after the loop exits.
}
_
7

このためにboolを使用する代わりに、フレームワークに組み込まれている 管理されたキャンセルフレームワーク の使用を検討する必要があります。

基本的に、CancellationTokenSourceを構築し、キャンセルを処理するために使用できるメソッドにCancellationTokenを渡します。

最後に、現在のメソッドはUIスレッドを決して取得しません。 UIをブロックしない場合は、Task.Runなどを使用してメソッドをThreadPoolに移動する必要があります。

3
Reed Copsey

別の方法として、 BackgroundWorker クラスを使用してジョブを実行することもできます。UIは対話型のままです。

1
Eugene