2011-07-13 25 views
4

Visual Studioで生成されたRCWでラップされた従来のVFP(FoxPro)COMコントロールを適切に処分しようとしています。コントロールは、コントロールを適切に破棄できるように呼び出すDestroyメソッドを公開します。 COMインスタンスを破棄する要求があった場合、コントロールのメソッドがバックグラウンドスレッドで実行されている可能性が非常に高いです。 VFPはシングルスレッドアパートメントモデルなので、Destroyを呼び出すときはVFP実行スタックに追加するだけです。マルチスレッド環境でのCOMの処理

COMインスタンスがいくつかのリソースをクリーンアップできるようにするには、Destroyを呼び出すのが理想的です。私の懸念は、VFP COMコントロールをインスタンス化すると、コントロールがホストされているVFP言語ランタイムインスタンスが実際に起動され、そのインスタンスがロックされる(非応答)ことがあります。このCOMコンポーネントは、大規模なエンタープライズ規模の20年前のレガシーアプリケーションの機能を公開しています。このコントロールのメソッドを呼び出そうとしている.NETスレッドがエラーを投げずにブロックする状況が見られました(常にレガシーのバグVFPコード)。これは頻繁には起こりませんが、バックグラウンドスレッドでVFP COMインスタンスのメソッドを実行し、そのスレッドがブロックされているかどうかを定期的にチェックするインスタンスマネージャを作成するように促すだけで十分な場合があります。 COMインスタンスとスレッドを監視し、監視する新しいインスタンスを再起動します。

これは、バックグラウンドメソッドが実行されているスレッドを破棄する正しい方法ですか?

COMコントロールが正しく破棄されるようにDestroyメソッドを呼び出そうとすると、魅力的になりますか?

if (_vfpThread != null) 
{ 
    try 
    { 
    if (_vfpThread.IsAlive) 
     _vfpThread.Abort(); 
    } 
    catch (ThreadAbortException) 
    { } 
    finally 
    { 
    _vfpThread = null; 
    } 
} 

if (_vfpInstance != null) 
{ 
    Marshal.ReleaseComObject(_vfpInstance); 
    _vfpInstance = null; 
} 

答えて

4

メソッド呼び出しが別のスレッドからの同じCOMオブジェクト上の任意の方法は、元の呼び出しが戻るまでブロックするを呼び出し、(常にSTAアパートで実行)VFPベースのCOMオブジェクトで保留されています(アパートを出る)。 つまり、Destroy()を同時に呼び出そうとしているスレッドは、その最初のスレッドを利用することになります。そのスレッドが自発的に終了することを知らない場合、理論的には、処理スレッドを無期限にブロックすることができます。つまり、です。もう1つのスレッド内からCOMオブジェクトの別のメソッドを呼び出すことによって、メソッドをすぐに終了するように第1スレッドに依頼する方法はありません。 _vfpThread.Abort()を呼び出す必要がありますが、このアプローチの安全性は主にVFPクラスの内部構造に依存します。 多くの場合、レガシーコードであるため、正常な終了を可能にするtry/catch/finallyセクションのようなものはありません。そのため、リソースはリリースされずに放置される可能性があります。 - 悪い!

もう1つの方法は、外部フラグをどこか(レジストリ、ファイル、何でも)設定することです。このフラグは、実行中のメソッドの中からその最初のスレッドによって読み取ることができます。もちろん、VFPクラスは、COMで公開されている各メソッドからフラグを読み取って、それに応じて迅速に処理する必要があることを認識する必要があります。

また、あなたのコードスニペットについて。 スレッドを中止しているコード内のThreadAbortExceptionを捕捉することは、このコードを実行しているスレッドがそれ自身を中断している場合にのみ意味を持ちます。それは代わりにメソッドから戻ることができるので、かなり厄介です。 (または、別のスレッドから_vfpThread.Abort()を呼び出している可能性があります) 通常のシナリオでは、ThreadAbortExceptionキャッチャーでラップする必要があるのは、呼び出しを実行する最初のスレッドのメインコードですCOMオブジェクトのすべてのビジネスメソッド。 理想的には、例外を再スローする前にコードがすべてのリソース/テーブルなどを正常に閉じることができるVFPメソッド自体と同じように、スタックの深いところに置くのが理想的です。 そして、あなたがThreadStartに渡したメインメソッドでは、メソッドから平和的に戻ってスレッドを終了させるか、スレッドプールに解放する以外は、同様のキャッチャーを使用します。

+0

上記のコードが、このVFPコンポーネントを管理するクラスのDisposeメソッド用であることは明らかではありませんでした。私は確かにVFPスレッドを正常にシャットダウンしようと試みることができますが、そうするには1分ほどかかることがあります。 VFPスレッドは、AutoResetEventを使用して、主スレッドにリソースを正常に解放したことを通知します。問題は、VFPスレッドをふるいにかけたときに何が起こるかです。 WaitOneが60秒後にタイムアウトした後、VFPスレッドをアボートします。これはコンポーネントの通常のシャットダウン/再起動には問題ありませんが、Disposeメソッドの場合は有効ではありません。廃棄するべきことは何ですか? – RMart

+0

これは正しいアプローチです。 VFPプロセッサをDispose外でシャットダウンするようにコードを修正します。これは別の問題です。また、愚かなThreadAbortException処理を指摘してくれてありがとう。 – RMart

0

はい、正しくコードを理解しました.-ありがとうございます。

vfpスレッドが60秒以内に正常に終了しない場合は、おそらく唯一のことです。 Disposeは何をすべきかという観点から、VFP COMクラス内で使用/開かれているので、残念ながらこのコードから隠されているすべてのアンマネージドリソースを解放するのが最善の方法です。したがって、COMオブジェクトが占有された場合、メインスレッドはそれらのリソースを強制的に解放することはできません。おそらく、VFPのtry-catchブロックにCOMビジネスメソッドの本体全体をラップし、catchセクションでリソース/クロージングテーブルを解放することができます。 try-catchブロックがメインスレッドから_vfpThread.Abort()を呼び出すことによって発生したThreadAbortExceptionを捕捉する可能性があります。

関連する問題