2

特定の時間実行できるようにしたい関数があり、それが自然に終了しない場合は中止します。これを行う最善の方法は何ですか?

私が考えた最善の方法は、別のスレッドで実行し、タイムアウトで終了するのを待ってから、それを強制終了するThread.Abort()ことです (関数に間違った種類のcatchブロックがある場合、これは機能しない可能性があります)。もう 1 つのオプション (どのように機能させるかがわかりません) は、スローを含むある種のプリエンプティブ タイマーです。

より良い方法はありますか?ある種の簡単なサンドボックス システムですか?


編集:私が実行しようとしている関数には、キャンセルする必要があるかどうかを確認するシステムがなく、(must notのように)追加できません。また、これは一種のテスト ハーネスなので、関数を強制終了する条件は、関数が暴走したことです。その場合、私はそれが正しく何かをしているとは期待できません。

4

8 に答える 8

5

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

スレッドが雑草に入った場合は、AppDomain を強制終了できます。

于 2009-08-04T04:32:03.937 に答える
2

実装したいのはBackgroundWorker. はBackgroundWorkerバックグラウンド操作を実行でき、バックグラウンド操作のキャンセルを通知するメカニズムを提供します。

バックグラウンド操作は、渡されたインスタンスのCancelプロパティを定期的にチェックし、値が.DoWorkEventArgstrue

インスタンスで Cancel プロパティを設定するには、開始インスタンスDoWorkEventArgsでメソッドを呼び出します。CancelAsyncBackgroundWorker

MSDNのドキュメントに良い例があります。そのページの下部にあるコミュニティの投稿と関連リンクも参照してください。


このブログ投稿も興味深いかもしれませんが、Thread.Abort を使用していますが、これは避けることをお勧めします... C# Set method timeout using Generics

于 2009-08-04T04:31:32.907 に答える
1

関数が終了しないのはなぜですか? それはどのような結果を生み出しますか?

私の最初の試みは、コードを十分にタイトにし、すべての「スタック」ケースを処理して、ウォッチドッグが必要ないようにすることです-リソースが解放されるのを待っている場合は、待機にタイムアウトを設定し、例外を適切に処理します.

これがなければ、必要に応じて Process.Kill を実行して、プロセス外のウォッチドッグを生成しようとします。これは Thread.Abort よりも効果的です。残忍な解決方法を選択する場合は、最後まで行ってみませんか?

于 2009-08-04T04:31:59.553 に答える
1

この問題に対する正気の解決策を見つけるために、全力を尽くしてください。例外はフロー制御ではなく、スレッドの中止はさらに悪いことです。つまり、スレッドで実行し、タイムアウト後にスレッドを中止することができます。

編集:別の解決策を見つけることをどれだけ奨励しているかについて、強い言葉遣いですが有効な説明を次に示します。 .html

于 2009-08-04T04:07:51.127 に答える
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
}
于 2009-08-04T04:39:53.953 に答える
1

関数のプロセスを簡単に中断できない場合は、タイマーを使用して現在のスレッドを中止する必要がある場合があります (別のスレッドで関数を実行することを回避できます)。現在のスレッドが中止されるとすぐに、この中止を Thread.ResetAbort() でリセットし、プログラムの他のステップを実行できます。

したがって、これに似たクラスを使用できます

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();
        }
    }
于 2009-08-04T07:00:04.263 に答える
0

Thread.Join() を使用して、スレッドの実行を制限できます。

于 2009-08-04T04:14:42.673 に答える
0

これはやり過ぎのように思えるかもしれませんが、技術的には希望どおりに機能する可能性があります。作業中のコードを 2 つに分割します。最初の部分はマネージャー、2 番目の部分はエグゼキューターになります。

Executor (あなたの場合) は、テストしたい機能を備えた単純なコマンド ライン アプリにすることができます。この時点でマネージャー アプリが行うことは、Process (System.Diagnostics) クラスを使用してコマンドライン アプリを呼び出すことです。プロセス クラスのメソッドの 1 つは WaitForExit で、コンソール アプリが終了するまで待機します。ただし、アプリが終了しない場合は、アプリを強制終了するまでの待機時間を指定できます。

これを使用すると、必要なものを取得できるはずです

于 2009-08-04T04:41:41.077 に答える