1

完了したら UI を更新するバックグラウンド スレッドがあります。Disposed された GUI を呼び出さないように、できるだけ安全にしようとしました。

void DoInBackground()
{
    try 
    {
       string result = ServerSideProcess();
*       if (!IsDisposed && !Disposing)
*          BeginInvoke(new StringDelegate(UpdateText), result);
    }
    catch (Exception ex)
    {
*       if (!IsDisposed && !Disposing)
*          BeginInvoke(new VoidDelegate(UpdateFailed));
    }
}


void UpdateText(string txt)
{
    if (!IsDisposed && !Disposing)
        textbox1.Text = txt;
}

void UpdateFailed() 
{
    if (!IsDisposed && !Disposing)
        textbox1.Text = "failed to get data from server";
}

override Dispose(bool disposing)
{
    if (disposing)
    {
        if (components != null)
            components.Dispose();
    }
    base.Dispose(disposing);
}

GUIメソッド内では十分に安全だと思います.UpdateText(string)またはUpdateFailed()内にいる間はDispose()は呼び出されません。どちらも同じスレッドで実行されるためです。 IsDisposing の場合は、後で実行するだけで十分です。しかし、(*) 内の部分が Dispose() を途中で取得しないことを確認するにはどうすればよいでしょうか。その結果、破棄するクラスで BeginInvoke が呼び出され、最終的にアプリケーションがクラッシュします。

(*) 部分の間に Thread.Sleep(2000) を追加し、Thread.Sleep の前後にブレークポイントを配置し、コントロールの外に移動して、BeginInvoke に到達する前に Dispose()d を取得することでテストしました。結果 - アプリケーションがクラッシュしました。ランタイムがこの不幸なコンテキスト切り替えシナリオを提供しないことをどのように知ることができますか?

4

4 に答える 4

4

これは、Backgroundworker によって無料で完全に解決される問題のようです。

使用しない理由はありますか?

于 2012-04-11T16:35:28.120 に答える
2

これを例外的な条件と呼びます。BeginInvokes の前後で try/catch を使用して、スローされる例外をキャッチし、明示的に処理します。

于 2012-04-11T16:34:19.863 に答える
0

以下は、実行時にエラーメッセージを表示しません。

BackgroundWorker bw = new BackgroundWorker();

public Form1()
{
    InitializeComponent();

    bw.DoWork += bw_DoWork;
    bw.RunWorkerCompleted += bw_RunWorkerCompleted;

    Shown += Form1_Shown;
}

void Form1_Shown(object sender, EventArgs e)
{
    bw.RunWorkerAsync();
    Thread.Sleep(1000);
    Dispose();
}

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    //This is your second thread.
    Thread.Sleep(2000);
}

void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    //This runs when the second thread is finished. Update here.
    Text = "Done";
}
于 2012-04-11T21:24:16.583 に答える
0

場合によってはDispose、コントロールのルーチンでロックを取得し、フラグを設定し、ロックを解放することで、正常にシャットダウンできる場合があります。更新ルーチンはロックを取得しBeginInvoke、フラグが設定されていない場合は実行し、ロックを解放する必要があります。ロックの主な目的は、更新ルーチンが を呼び出すことを決定した後BeginInvoke、更新が行われるまでコントロールが破棄されないようにすることです。

そうは言っても、多くの点でBeginInvoke、コントロールがあなたの下から破棄された場合に発生する例外を単に実行して飲み込む方がクリーンだと思います。コントロールが生きている場合TryBeginInvokeは a を実行し、それ以外の場合はBeginInvokereturn を返すa が実際に存在する必要がありますが、残念ながら、コントロールのプロセスに自分自身を挿入したり、例外を発生させたりせずに作成するレースフリーの方法はありません。そしてそれを窒息させます。TrueFalseDispose

于 2012-04-11T23:59:16.237 に答える