2009-08-04 10 views
2

私は、一定の時間実行する機能を持っていますが、それが終了していなければ中止します。 これを行う最善の方法は何ですか?"Watch Dog"やサンドボックスシステムをC言語で#

私はそれが死ぬと、それを殺すためにThread.Abort()を使用するための機能がcatchブロックの間違った種類を持っている場合、これは動作しないかもしれません(タイムアウトして待って、別のスレッドで実行するだろうと考えている最高)。別のオプション(私は仕事をする方法がわからないもの)は、それをスローするプリエンプティブタイマーのようなものです。

良い方法がありますか?簡単なサンドボックスシステムのいくつかの種類ですか?


編集:私はそれをキャンセルする必要があるかどうかを確認するために、任意のシステムを持っていない実行しているつもりだ機能と私は(のようではないしなければならない)、それを追加することはできません。また、これは種類のテストハーネスなので、私がその機能を殺す状況は、それがうまく走っているということです。その場合、私は何かを正確にすることは期待できません。

答えて

5

これはあまりにも多すぎるかもしれませんが、そのスレッドをホストしているものをAppDomainにロードするかどうかを調べることができます。 AppDomainは基本的に.NETサンドボックスです。

スレッドが雑草に入る場合は、AppDomainを殺すことができます。

+0

'AppDomain'境界を越えて機能する戻り値とコールバックを得る方法はありますか? – BCS

+0

Thread.Abort()よりも優れたBackgroundWorkerを使用できない場合は、コードをAppDomainにロードすることをお勧めします。 –

+1

デリゲートを介して別のAppDomainの任意のメソッドを呼び出すためのラッパーコードを含むかなり良い記事があります。http: //blogs.geekdojo.net/richard/archive/2003/12/10/428.aspx。メソッドコールから結果を返すのはうまくいきましたが、何らかの理由で引数を渡すことができませんでした。多分あなたはより良い運を持っているでしょう。 –

1

この問題の根本的な解決策を見つけるには、あなたの力ですべてを行います。例外はフロー制御ではなく、スレッドアボートは非常に悪いです。つまり、スレッドで実行し、タイムアウト後にスレッドを中止することができます。

編集:ここで強く文言であるが、私は別の解決策を見つけるためにあなたを奨励していますどれだけの有効な、説明:http://tdanecker.blogspot.com/2007/08/do-never-ever-use-threadabort.html

+0

すべての良い点だこと。しかし、私の場合、私はいくつかの緩和の考慮事項があります:1)機能は外部の状態と相互作用しないので、機能は純粋な機能として扱うことができます2)それを殺さないという副作用は多かれ少なかれ致命的です3)私は実際に何をしても「今すぐ止める」必要があります。 – BCS

0

あなたがスレッドの実行を制限するThread.Join()を使用することができます。

2

具体的にはBackgroundWorkerです。 BackgroundWorkerは、バックグラウンド操作を実行することができ、そのバックグラウンド操作のキャンセルを通知するためのメカニズムを提供します。

DoWorkEventArgsインスタンスでは、バックグラウンド操作でCancelプロパティが定期的にチェックされ、値がtrueの場合、正常に終了します。 DoWorkEventArgsインスタンスのCancelプロパティを設定する

は、開始BackgroundWorkerインスタンス上CancelAsyncメソッドを呼び出すことによって達成することができます。

MSDN documentationには良い例があります。また、そのページの下部にあるコミュニティの貢献と関連リンクを参照してください。


あなたはまた、私は本当にあなたが避ける推薦されても、それはThread.Abortを使用して、興味深いこのブログの記事を見つけることができます... C# Set method timeout using Generics

+0

良い一般的な解決策+1私の場合は実行できません。 – BCS

+0

なぜですか?詳細を提供できますか? –

+0

@ spoon16:私の編集とコメントを参照してください。短いバージョン:関数がクローズドソースlibにあった場合にはうまくいきませんと同じ理由です。 – BCS

1

はなぜ関数が終了していないでしょうか?それは何の結果ですか?

私が最初に試したのは、完全にコードが詰まっていて、すべての「スタック」ケースを処理するためです。ウォッチドッグが不要なので、リソースが解放されるのを待っている場合は、例外を適切に処理します。

これは短く、私はプロセス外のウォッチドッグを生成し、必要に応じてProcess.Killを実行しようとします。これはThread.Abortよりも効果的です。残酷な解決策をとっているなら、どうしたらいいのですか?

+0

ウォッチドッグは決して起動しません。しかし、私もバグはあってはいけません。プロセス外のソリューションは、データを前後に取得するのが醜いため、少し醜いです。 – BCS

1

私は問題を正しく理解していないかもしれませんが、ロジックを機能自体に入れないのはなぜですか?例(C#):

public void someLongFunction() 
{ 
    DateTime start = DateTime.Now; 
    while (DateTime.Now <= start.AddMinutes(5)) // assuming 5 mins run time 
    { 
     // long processing code here 
     if (DateTime.Now > start.AddMinutes(5)) 
      break; 
     // more long processing code 
    } 
    // thread clean up etc. here 
} 
+0

要するに:私は許可されていません。 – BCS

0

これは過度のように思えるかもしれませんが、技術的にはあなたが望むように動作する可能性があります。 2で作業しているコードを分割します。最初の部分はマネージャになり、2番目の部分は実行者になります。

Executor(あなたの場合)は、テストする機能を備えた単純なコマンドラインアプリにすることができます。この時点であなたのマネージャーアプリケーションが行うのは、Process(System.Diagnostics)クラスを使用してコマンドラインアプリケーションを呼び出すことです。プロセスクラスのメソッドの1つは、WaitForExitです。これは、コンソールアプリケーションが終了するまで待機します。しかし、アプリケーションが終了しない場合は、強制的に終了するまでに待機する時間を指定することができます。あなたが簡単にあなたの関数の処理を中断することができない場合は、現在のスレッドを中止するためにタイマーを使用する必要がありますが

+0

argsと戻り値を前後で取得すると、あまりにも複雑になります。私はそれよりもエラーケースで暮らす方が喜んでいるでしょう。 – BCS

1

欲しいものを得ることができる必要があり、この(それは実行するためにあなたを回避を使用して

他のスレッドでのあなたの関数)。現在のスレッドがアボートするとすぐに、このアボートをThread.ResetAbort()で再開し、プログラムの他のステップを実行することができます。

だから、この1

using System.Threading; 
using System.Timers; 

namespace tools 
{ 
    public class ThreadAbortTimer 
    { 
     public ThreadAbortTimer(int timeout) 
     { 
      _CurrentThread = Thread.CurrentThread; 
      _Timer = new System.Timers.Timer(); 
      _Timer.Elapsed += _Timer_Elapsed; 
      _Timer.Interval = timeout; 
      _Timer.Enable = true; 
     } 

     /// <summary> 
     /// catch the timeout : if the current thread is still valid, it is aborted 
     /// </summary> 
     /// <param name="sender"></param> 
     /// <param name="e"></param> 
     void _Timer_Elapsed(object sender, ElapsedEventArgs e) 
     { 
      lock (typeof(ThreadAbortTimer)) 
      { 
       if (_CurrentThread != null) 
       { 
        _CurrentThread.Abort(); 
        _CurrentThread = null; 
       } 
      } 
     } 

     /// <summary> 
     /// timer that will check if the process lasts less than 30 seconds 
     /// </summary> 
     private readonly System.Timers.Timer _Timer; 

     /// <summary> 
     /// current thread to abort if the process is longer than 30 sec 
     /// </summary> 
     private Thread _CurrentThread; 

     /// <summary> 
     /// stop the timer 
     /// </summary> 
     public void Disable() 
     { 
      lock (typeof(ThreadAbortTimer)) 
      { 
       _Timer.Enabled = false; 
       _CurrentThread = null; 
      } 
     } 

     /// <summary> 
     /// dispose the timer 
     /// </summary> 
     public void Dispose() 
     { 
      _Timer.Dispose(); 
     } 
    } 
} 

に似たクラスを使用することができ、その後、あなたはこのようにそれを使用することができます:

using (var timer = new ThreadAbortTimer(timeout)) 
    { 
     try 
     { 
      // the process you want to timeout 
     } 
     catch 
     { 
      timer.Disable(); 
      Thread.ResetAbort(); 
     } 
    } 
+0

ちょっとしたトリック+1ですが、最終的なブロックではありませんか? – BCS

+0

しかし、本質的に危険なので、あなたは "タイプをロック"してはいけません。詳細については、「タイプをロックしない」のgoogleをご覧ください。そのために* private *スタティックメンバ(オブジェクト型)を使用してください。または、この例では、プライベートインスタンスメンバーを使用することをお勧めします。そうしないと、すべてのインスタンスが互いに同期します。 –