1

オブジェクトのインスタンスを作成および設定し、オブジェクトに作業を行うように指示するフォームがあります。このプロセスは時間がかかるため、フォームには、何かが起こっていることをユーザーに知らせるステータス メッセージが表示される領域があります。メッセージは setMessage(string msg) 関数で設定されます。フォームがイベントに反応し続けるようにするために、オブジェクトを実行する新しいスレッドを作成し、デリゲートとして setMessage 関数を渡して、オブジェクトがフォームにステータス メッセージを設定できるようにします。この部分は正常に動作しています。メイン フォームはレスポンシブであり、その setMessage 関数に投稿されたメッセージは期待どおりに表示されます。

このプロセスは長く、多くのステップで構成されているため、プロセスが完了する前にユーザーがプロセスを終了できるようにしたいと考えています。これを行うために、_stopRequested という volatile bool と、その値を返す shouldStop() という関数を作成しました。これもデリゲートとしてオブジェクトに与えられます。オブジェクトは、定期的に shouldStop() をチェックすることで、終了する必要があるかどうかを判断できます。それが true の場合は、正常にシャットダウンします。

最後に、Windows コントロールはスレッド セーフではないため、コントロールを作成したスレッド以外のスレッドがコントロールを操作しようとすると、コンパイラは警告を発します。したがって、setMessage 関数は、これをテストし、ワーカー スレッドから呼び出されている場合は親スレッドを使用して関数を呼び出す if ステートメントでラップされます ( http://msdn.microsoft.com/en-us/library/ms171728を参照)。 (説明については v=vs.80).aspx )。

ユーザーがシャットダウンを要求すると、問題が発生します。メイン フォームは _stopRequested を true に設定し、子スレッドが終了するのを待ってからアプリケーションを閉じます。これは、_child.Join() を実行することによって行われます。現在、親スレッド (フォームを実行しているスレッド) は結合状態にあり、何もできません。子スレッド (長いプロセスを実行している) は、停止フラグを検出してシャットダウンを試みますが、シャットダウンする前に、setMessage デリゲートを呼び出してステータス メッセージを送信します。そのデリゲートは、メッセージを設定するスレッド (子) がコントロールを作成したスレッド (親) とは異なることを把握し、親スレッドで関数を呼び出すメイン フォームをポイントします。もちろん、親スレッドは結合状態にあり、子スレッドが終了するまでテキスト ボックスにテキストを設定しません。子スレッドは、呼び出したデリゲートが戻るのを待っているため、終了しません。インスタントデッドロック。

スレッドに終了を通知する例と、子スレッドが親スレッドにメッセージを送信する例を見つけましたが、両方が同時に発生している例は見つかりません。このデッドロックを回避する方法について、誰かが私にいくつかの指針を教えてもらえますか? 具体的には、アプリケーションを閉じる前に子スレッドが終了するまでフォームを待機させ、待機中も作業を実行できるようにしたいと考えています。

アドバイスをいただきありがとうございます。

4

1 に答える 1

0

1-(lazy) 新しいスレッドからメソッドをディスパッチしてロックしないようにする

2-(再考) メイン UI スレッドは子スレッドを制御できる必要があるため、_stopRequested と shouldStop() を忘れて childThread.Abort() を実装します。abort はスレッドを強制終了しませんが、ThreadAbortException を送信します。処理されるか、キャンセルされることさえあります

catch(ThreadAbortException e)
{
    ReleaseResources();
}

次のようなさまざまなチェックを行って、ReleaseResources を安全にします。

resource != null

また

resource.IsClosed()

ReleaseResources は、通常どおり中止せずに、また中止によっても呼び出す必要があります。

3-(可能であれば)メインスレッド呼び出し ReleaseResources() を介して子を停止します

これらを組み合わせて実装する必要がある場合があります。

于 2013-05-28T13:53:59.097 に答える