2009-07-20 7 views
1

で起動我々は、ダイアログや他のユーザーとの対話をポップする必要がバックグラウンドスレッドで実行されているいくつかのコードを持っているので、我々は、UIスレッドへの通常のInvoke呼び出しを実行します。タイムアウト

Control.Invoke(SomeFunction); 

void SomeFunction() 
{ 
    ... 
} 

をしかし、我々 UIスレッドがInvoke呼び出しに即座に応答しないことがあるため、UIスレッドが現在、まだ返されていなかったクロスプロセスDCOM呼び出しを実行していたことがわかりました。 DCOMコールが戻ってくると、私たちの機能は呼び出されましたが、それまではInvokeコールがハングアップしたように見えました。

このため私のソリューションは、タイムアウトを導入した

ManualResetEvent invokeEvent = new ManualResetEvent(); 
var result = Control.BeginInvoke(SomeFunction, invokeEvent); 

if (!invokeEvent.WaitOne(1000)) 
    throw new Exception("Not responding"); 

Control.EndInvoke(result); 

void SomeFunction(ManualResetEvent invokeEvent) 
{ 
    invokeEvent.Set(); 

    ... 
} 

これは、「私のマシンの感覚の作品」で働いていたが、それは欠陥の数を持っていました。

http://www.codinghorror.com/blog/images/works-on-my-machine-stamped.png

  • は、まず機能はまだタイムアウトが発生した場合でも、呼び出される - DCOMの呼び出しが実際に完全にハングアップしていなかったならば、それは最終的に第二
  • 実行され、明白な恐ろしいレースがあります条件
  • 最後に、最初の二つのことが解決できたとしても、全体のこと

の全体の「Arrgh」-nessがあり、我々はまだ世代を持っていますまあまあ。これを解決する良い方法はありますか?

答えて

0

クロスプロセスDCOM呼び出しを別のスレッドに移動します。あなたは明らかにです。は完全に受け入れられないUIスレッドをぶら下げています。それを修正して、あなたのファントムの問題(OP)もなくなります。

+0

私たちはクロスプロセスDCOM呼び出しを行うコードを所有していないと申し訳ありません。たとえそうしたとしても、これを一般的な問題として解決する必要があります。これは、この一般的な問題の原因となる他のコードがロードされる可能性があります。良いアイデア –

0

これはGUIスレッドで何かを実行する際に発生する一般的なスレッド問題で、この現象はすべての開発者に影響します。

実際の進行状況ダイアログを表示するスレッドとDCOM呼び出しを実行する別のスレッドを作成する場合は、2つのスレッド間でManuaResetEvent同期を移動するだけで済みます。進行状況フォームを作成する別のスレッドには独自のメッセージキューが作成され、DCOM呼び出しを実行するために使用される2番目のスレッドはGUIスレッドをロックする必要がないため、GUIスレッドをロックしないという利点があります。

それはいくつかの慎重なsycnhronizingを必要としますが、一度に行わず、それが行動に見て美しいです:

private ManualResetEvent _event = new ManualResetEvent(false); 
... 

private void StartTheComProgressCall() 
{ 
    _event.Reset(); 

    ThreadPool.QueueUserWorkItem(StartProgressDialog); 
    ThreadPool.QueueUserWorkItem(StartDCOMCall); 

    // there's various possibilities to perform here, we could ideally 1) wait on the 
    // event to complete, 2) run a callback delegate once everything is done 
    // 3) fire an event once completed 
} 

private void StartProgressDialog(object state) 
{ 
    ProgressDialog dialog = new ProgressDialog(); 
    dialog.Show(); 

    while(!_event.WaitOne(0)) 
     Application.DoEvents(); 

    dialog.Close(); 
} 

private void StartDCOMCall() 
{ 
    ... 
    <perform your DCOM routines here> 

    // once the call is done, remember to trigger that it's complete 
    // so that blocking threads can continue to do what they need to do 
    _event.Set(); 
} 

ノート 一部がApplication.DoEvents()メソッドを使用して反論が、DoEventsは保留中のWindowsメッセージを強制することを検討するかもしれません現在の呼び出しスレッドのメッセージキュー上で処理され、GUIスレッドではなく別のスレッド(進行状況ダイアログを作成したスレッド)で呼び出しが行われたため、それを使用することでそれ以上の倫理的な "コードの匂い" 。どんなツールや技術を使っても、私たちは仕事を手助けする必要があります。

関連する問題