0

説明 (.Net Framework 3.5/Windows7/VS12) : 1) 操作は非同期で実行できるタイプです。次のように、 Executed という名前のイベントを通じて他のオブジェクトに通知します。

_Operation.Executed += OperationExecuted;

2) このイベント内で、次のように StopProgress() を呼び出します。

private void OperationExecuted (object sender, OperationEventArgs e)
{
    StopProgress(); 
}

3) StopProgress() は次のとおりです。

public void StopProgress()
{
    if (InvokeRequired)
    {
        Invoke(new MethodInvoker(StopProgress));
        return;
    }

    lblTemp.Text = "operation complete. ";// 1
    //progressBar1.Visible = false; // 2

    // with added locks the app totally hangs
    //lock (progressBar1)
    //{
    //    progressBar1.Visible = false;
    //}
}

"1" とマークされた行 ( StopProgress() 内) にコメントを付け、"2" のコメントを外す (これは望ましい動作です) と、ときどき競合状態に遭遇します (アプリを 5 ~ 10 回実行した後、競合状態に遭遇します)。行「1」では、それは決して起こりません。スローされる例外もありません(キャッチ/アンキャッチ)。問題は「ProgressBar」自体に関連していると想定しています。そうでない場合、おそらくここではどうなるでしょうか。競合状態 (脆弱なコード セクション) を追跡する方法に関する提案も大歓迎です。ありがとう。

4

2 に答える 2

2

これを説明するのは難しいですが、このコードにはデッドロックを引き起こす強力なアンチパターンがいくつかあります。

まず、Control.Invoke() を使用して、進行状況バーの更新が UI スレッドで確実に行われるようにします。したがって、更新は1 つのスレッドでのみ発生することが既にわかっているため、 lockステートメントを使用する必要はまったくありません。というわけでロックを外します。

Control.Invoke() の使用は悪いアンチパターンです。UI スレッドがデリゲート ターゲットを実行するまで完了できないため、特にデッドロックが発生しやすくなります。デッドロックは、スレッドの完了を待機する UI スレッドで実行される他のコードがどこかにある場合に発生します。これは決して起こりません。スレッドは、UI スレッドがアイドル状態になるまで完了できない Invoke() 呼び出しでスタックします。UI スレッドはアイドル状態になることができず、スレッドが完了するまで待機しています。デッドロックシティ。Invoke() は、絶対に必要な場合にのみ使用し、デッドロックを引き起こす可能性があることを恐れてください。代わりに常に BeginInvoke() を優先します。待機しないため、デッドロックを引き起こすことはありません。そして、ここでは Invoke() は必要ありません。その戻り値を知る必要はありません。

Control.InvokeRequired の使用もアンチパターンです。ほとんどの場合、メソッドがワーカー スレッドから呼び出されることはわかっています。したがって、InvokeRequired をテストしても意味がありません。true であることが期待されますfalse の場合、非常に悪いことが起こります。ユーザーがフォームを閉じ、ワーカー スレッドが実行を継続できるようになったときに発生する可能性が非常に高いです。通常、これによりコードが ObjectDisposedException でクラッシュします。しかし、コードはそこに到達しません。それが発生する前に、 Invoke 呼び出しまたはlockでデッドロックする可能性があります。InvokeRequired を使用する必要がありますが、false の場合は InvalidOperationException をスローします。これで、問題の原因を突き止める機会を与える診断が追加されました。

これらのことを既に処理している .NET クラスを使用して先に進みます。BackgroundWorker は、あなたがやろうとしていることをすべて手作業で行います。また、ワーカー スレッドがまだ実行されている状態でユーザーがフォームを閉じるという問題に対処することもできます。この回答の主題。

于 2013-06-24T10:15:29.310 に答える