2009-03-27 2 views
5

大規模な自動化プロセスの一環として、別のマシンでいくつかの作業呼び出しサービスを実行するサードパーティAPIを呼び出しています。最近、他のマシンが利用できなくなるたびに、リモートサーバーに接続しようとしているときに、APIコールが時には最大40分間スピンしてしまうことが発見されました。C#でのスレッディングの合理的な使用?

私たちが使っているAPIはタイムアウトを指定する方法を提供しておらず、私たちのプログラムはそれほど長く待たされたくないので、スレッドがタイムアウトを強制する良い方法だと思っていました。結果のコードは次のようになります。

Thread _thread = new Thread(_caller.CallServices()); 

_thread.Start(); 
_thread.Join(timeout); 

if (_thread.IsAlive) 
{ 
     _thread.Abort(); 
     throw new Exception("Timed-out attempting to connect."); 
} 

は基本的に、私はAPICall()実行させたいが、それはまだ、タイムアウトが経過した後に起こっている場合、失敗するそれを殺すし、上に移動しようとしていると仮定します。

私はC#でスレッドへの新たなんだと.NETランタイム上で、私は二つの関連質問をしようと思いましたので:

は、私は「何のための.NETライブラリでより良い/より適切なメカニズムがあります私は何をしようとしているのでしょうか?

答えて

5

Thread.Abort()は、スレッドが中止する要求であり、適時に行うことを保証しません。

リモートサービスホストのアドレスが分かっている場合は、(プログラムで)リモートサービスホストのアドレスを知っている場合は、あなたがサードパーティのAPIに制御を移す前に、あなたはそれをpingする必要があります。

のBackgroundWorkerを使用していない場合は、それが終了するから、あなたのプログラムを保持しませんので、あなたは、trueにスレッドのIsBackgroundThreadを設定することができます。

3

悪い考え。 Thread.Abortは、このような中断されたAPIコールによって残された混乱を必ずしも解決しません。

呼び出しが高価な場合は、呼び出しを行う別の.exeを作成し、コマンドラインまたは一時ファイルを使用して引数を渡すことを検討してください。スレッドを強制終了するよりも安全に.exeを強制終了することができます。

0

それは可能性があります誰もがサードパーティのAPIを理解することなく確実に言うことはできませんでした。そのようなスレッドを中止すると、コンポーネントがablでないかもしれない無効な状態になる可能性がありますeからリカバリするか、または割り当てられたリソースを解放しません(あなたのルーチンのうちの1つが途中で実行を停止した場合はどう思いますか?あなたのプログラムが存在する状態について何らかの保証をすることができますか?)。

Cicilが提案したように、まずサーバーにpingを実行することをお勧めします。

3

デリゲートを使用することもできます。作業を行うメソッドのデリゲートを作成し、デリゲートでBeginInvokeを呼び出し、引数を渡し、コールバック関数を使用して戻り値を処理します)...

...すぐにBeginInvokeをした後、あなたは非同期デリゲートが終了するのを指定された時間を待つことができる、そしてそれはその指定された時間内にない場合は、上の移動
public delegate [ReturnType] CallerServiceDelegate 
      ([parameter list for_caller.CallService]); 

    CallerServiceDelegate callSvcDel = _caller.CallService; 
    DateTime cutoffDate = DateTime.Now.AddSeconds(timeoutSeconds); 
    IAsyncResult aR = callSvcDel.BeginInvoke([here put parameters], 
              AsynchCallback, null); 
    while (!aR.IsCompleted && DateTime.Now < cutoffDate) 
     Thread.Sleep(500); 
    if (aR.IsCompleted) 
    { 
     ReturnType returnValue = callSvcDel.EndInvoke(aR); 
     // whatever else you need to do to handle success 
    } 
    else 
    { 
     callSvcDel.EndInvoke(aR); 
     // whatever you need to do to handle timeout 
    } 

注:書かAsynchCallbackはできる限りコードがEndInvoke()から戻り値を取得するため、nullにすることもできますが、必要に応じてCallService()メソッドでAsynchCallbackデリゲートを呼び出し、戻り値instaedを渡すことができます。

+0

どのようにタイムアウトを処理しますか?不足しているサーバーに接続するためにコンポーネントが最大40分間試し続けますか?私は、コンポーネントが接続しようとするのを止める方法について質問したと思います。 – Cybis

+0

申し訳ありません、サンプルコードを追加する編集中です...タイムアウトの質問は、DateTime.Now

0

アプリケーションは長期間実行されるのですか、それとも実行に必要なアプリケーションほどですか?後者の場合、私は個人的にはThread.Abort()オプションの使用を検討します。純粋主義者の視点(リソース管理など)では最も望ましい方法ではないかもしれませんが、実装するのは確かに簡単です。

別個の実行可能ファイルの考え方が理にかなっています。おそらく別のオプションは、AppDomainsを使用することです。私はこの分野の専門家ではありません(私はこれに対する改良/修正を歓迎します)。しかし、わかっているように、API呼び出しを別のDLLに入れて別のAppDomainにロードします。 API呼び出しが完了するか、API呼び出しを中止する必要がある場合は、AppDomainをDLLとともにアンロードできます。このには、単純なThread.Abort()にはないリソースをクリーンアップするという利点があります。

関連する問題