3

以下に示すように AddListBoxItem 関数内で呼び出しを使用すると、ソフトウェアが応答しなくなり、フリーズしますが、BeginInvokeを使用すると機能します。なぜそれが起こっているのですか?

ビジュアル スタジオ 2010、C# 4.0

 private void button2_Click(object sender, EventArgs e)
{
    var watch = Stopwatch.StartNew();
    Parallel.For(2, 20, (i) =>
    {
        var result = SumRootN(i);
        AddListBoxItem("root " + i + " : " + result);
    });
    AddListBoxItem(watch.ElapsedMilliseconds.ToString());            
}

private delegate void AddListBoxItemDelegate(object item);

private void AddListBoxItem(object item)
{
    if (this.listBox1.InvokeRequired)
    {
        this.listBox1.Invoke(new AddListBoxItemDelegate(this.AddListBoxItem), item);
    }
    else
    {
        this.listBox1.Items.Add(item);
    }
}
4

3 に答える 3

3

UI スレッドはParallel.For、続行する前に完了するまで待機します。つまり、完了するまでそれ以上の UI メッセージを処理することはできません。

ワーカー スレッドが を呼び出すとInvoke、UI スレッドがデリゲートを処理するまで待機してから続行します。したがって、基本的には UI スレッドが解放されるのを待っています。

したがって、デッドロックが発生します-UIスレッドは、UIスレッドを待機しているタスクを待機しています...BeginInvokeタスクスレッドはデリゲートがUIスレッドで処理されるのを待機しないため、機能します。

Parallel.For最初から UI スレッドを呼び出さないことをお勧めします。とにかく完了するまで UI をブロックすることになりますが、これはお勧めできません。すべてをバックグラウンド スレッドで実行します。その後、必要に応じて引き続き使用できInvokeます。また、計算を実行している間も、UI は応答します。

于 2011-10-02T19:58:27.337 に答える
3

UIスレッドをデッドロックしているようです。your は完了button2_Clickするまで終了せず、特にが完了するまでメッセージループイベントを処理できないため、これは完全に理にかなっています。別のスレッドにいる場合、メッセージ ループ イベントを使用し、その項目が処理されるまで戻りません。つまり、何も実行されず、/が完了することはありません。Forbutton2_ClickInvoke Forbutton2_Click

この作業をキューBeginInvokeに入れるだけで、すぐに戻ります。これは、完了できることを意味しこれにより完了が許可され、メッセージ ループ イベントを処理できるようになります (UI の更新)。BeginInvokeForbutton2_Click

于 2011-10-02T20:01:59.097 に答える
1

これは、メインスレッドが上記の Click イベントでブロックされ、AddListBoxItem が終了するのを待って、buttion2_click イベントが返されるのを待っているためだと思います。
UI に Controller ロジックを含めるべきではないため、Click が別のスレッドでロジックをコールバックしないという主な問題があります。

ロジックのスレッドを実装した後、GUI はブロックされず、どのような状況でも簡単に更新されます。

于 2011-10-02T20:01:56.843 に答える