1

WinFormsアプリケーションで実行されている最小化を処理するための2つのバックグラウンドスレッドと1つのスレッドがあります。プログラムが終了するとき、私はこの方法を使用します。

private void MyForm_Closing(object sender, FormClosingEventArgs e)
    {
        if(labelsUpdaterThread.IsAlive == true)
            labelsUpdaterThread.Abort();
        if(printNotifyThread.IsAlive == true)
            printNotifyThread.Abort();
        if(minimizeThread.IsAlive == true)
            minimizeThread.Abort();
    }

labelsUpdaterThreadとprintNotifyThreadは常に実行されます。ご想像のとおり、MinimizeThreadは、親フォームが最小化されている場合にのみ実行されます。これが私の問題です:

上記のメソッドでthread.abortメソッドが呼び出された場合、MdiParentフォームの右上にある「X」は何もしません。クリックしても効果はありません。

上記のメソッドでthread.abortメソッドが呼び出されていない場合、スレッドはバックグラウンドスレッドであっても、使用できなくなったMdiParent上のリソースにアクセスしようとしているため、MdiParentを閉じると例外がスローされることがあります。

なぜこれが起こっているのかわかりませんが、私にはあまり意味がありません。助けてくれてありがとう!

4

3 に答える 3

4

私はあなたが決して電話してはいけないという点でポール・アレクサンダーの答えに同意します、それは同期を処理するための恐ろしい方法です。Thread.Abort

さらに、ここでは関心の分離がひどいです。スレッドは、フォーム内のリソースに直接アクセスしないでください。間に何らかの抽象化/共有状態が存在する必要があります。これは、両方の側(スレッドとフォームであるため、インスタンスをスレッドセーフにするようにしてください)によって変更および読み取られます。

そうは言っても、これらの変更を行うことができなかった場合は、Closeメソッドで、Thread.Abortそれぞれの周りにtry/catchステートメントを指定して別のスレッドのメソッドを呼び出します。少なくともどこかにエラーを記録します。

別のスレッドでへの呼び出しを実行するThread.Abort場合、UIスレッドをブロックしないでください。これは、への呼び出しThread.Abortが瞬時に行われることが保証されていないためです。UIスレッドをブロックすると、Xがグレー表示され、UIスレッドはWindowsメッセージを処理できなくなります。 (これは、関心の分離をより適切に行うためのガイドにもなります)。

ただし、フォームとスレッドの間で共有されるリソースを抽象化し、適切なキャンセルメカニズムを提供するように移動する必要があります。

状態を共有するクラスにリソースを抽象化する場合、フォームは閉じるときに何もする必要はありません。スレッド呼び出しスタックには状態を持つオブジェクトへの参照があり、それらのスレッドでabortを呼び出すことができます。フォームやスレッドが何かを共有することを心配する必要はありません。

そこから、適切な協調キャンセルメカニズムを導入できます(協調キャンセル。タスクが.NET 4.0でサポートしている場合は、それが利用可能であれば)。

于 2011-01-04T21:48:25.307 に答える
0

Abort呼び出しは、おそらく例外をスローしています。abortを呼び出す前に、ポインターが有効であり、スレッドがまだ有効(破棄されていない)であることを確認してください。

また、Visual Studioで、Debug \ Exceptions ...を開き、すべての例外の[throw]列にチェックを入れて、問題が発生したときに表示されるようにします。

于 2011-01-04T21:18:08.127 に答える
0

まず、.Abort()の呼び出しを削除し、二度と使用しないでください。スレッドは、Abortを呼び出して終了しないでください。基本的にスレッドをクラッシュさせ、リソースを適切に解放したり、システムハンドルを解放したりする機会を与えません。代わりにを作成ManualResetEventし、スレッドで確認してください。イベントが設定されると、それらは終了する必要があります。

スレッド1

while( ! _stopEvent.WaitOne(0) )
{
  ...do my thready work

}

そして最後に

private void MyForm_Closing(object sender, FormClosingEventArgs e)
{
  _stopEvent.Set();
  labelsUpdaterThread.Join();
  ...
}

アプリケーションが存在するときにスレッドが適切に終了するかどうかを気にしない場合は、設定するだけでIsBackground = true、アプリケーションの終了時にスレッドが自動的に終了します。

于 2011-01-04T21:21:56.960 に答える