2012-02-11 28 views
4

計算量が多い問題については、プログラムが費やしたCPU時間を制限したい。プログラムが一定時間内に解決策を見つけられない場合、プログラムを終了させたい。プログラムが永遠に解決策を探すのではなく、何も見つからなければ終了するべきです。プラットフォームが重要な場合、これはUNIX用です。これはどのように達成できますか?指定された時間プログラムを実行する方法は?

+0

この質問を書いたのですが、[あなたの答えを書き込む前に[Cのアルゴリズムを40秒間実行する方法](http://stackoverflow.com/q/9239909/1168156)が閉鎖されていましたか?それともなぜあなたはそれをやりましたか? – LihO

+1

なぜ3分以内にあなた自身の質問をしていますか? –

+0

私は基本的にあなたが言いました質問への答えを書いていました。私はこれが本当に興味深い問題だと感じました。私が説明したテクニックを使って答えを見つけることができませんでした。私は、元の質問はかなり簡潔かもしれないが、個人的に私はそれが全く不明確であるとは思わないと思います。 –

答えて

9

別のPOSIXソリューションは、信号を使用することです:

#include <unistd.h> 
#include <csignal> 

std::sig_atomic_t volatile done = 0; 

void game_over(int) { done = 1; } 

int main() 
{ 
    std::signal(SIGALRM, game_over); 
    alarm(5); // this program will self-destruct in 5 seconds 

    while (!done) 
    { 
     do_my_thing(); // or whatever; make sure this returns frequently 
    } 
} 

(これは、非常に少数の合法的かつ重要な用途の一つでありますvolatile:。我々はwhile (!done)条件を最適化するから、コンパイラを防ぐ必要があり、それはループ本体の内側に触れたことがないているため、コンパイラは、doneを突然変異させることができることを見ていない)

POSIXジstd::signalの使用を嫌う、それ自身の、より強力なsigactionを支持する。興味がある場合はマニュアルを参照してください。しかし、警告を発する単純な目的のためには、この解決策で十分です。

プログラムで中断ポイントが全くない場合(つまり、doneをチェックできるポイント)、シグナルハンドラでabort()に電話することもできます。

+0

'alarm'はリアルタイム秒を表し、questionは「プログラムが費やしたCPU時間」を指定します。このテクニックはその場所では便利ですが、おそらくこの回答が実際に答える質問の欺瞞があります。 –

+0

@SteveJessop:代わりに仮想処理時間が必要な場合は、 'setitimer'を使い、代わりに' SIGVTALRM'を処理できます。 –

5

考えられる方法は、望ましい時間のプロセス制限を設定することです。 setrlimit()で設定されたUNIXの制限は、実行時環境によって監視され、ソフト制限とハード制限の両方をサポートします。ソフト限界に達すると、信号がトリガされる。プログラムがラップアップされるべきであることを示すフラグをセットする。厳しい制限に達すると、プログラムはtermintedされるべきです(これはMacOSでは動作しません)。ここでは、簡単なプログラム例は次のとおりです。シングルスレッド化と自己完結型だ

#include <sys/resource.h> 
#include <iostream> 
#include <signal.h> 

sig_atomic_t finished = false; 
void limit(int) 
{ 
    finished = true; 
} 

int main() 
{ 
    signal(SIGXCPU, limit); 
    struct rlimit limit; 
    limit.rlim_cur = 2; 
    limit.rlim_max = 3; 
    setrlimit(RLIMIT_CPU, &limit); 

    unsigned long long i(0); 
    while (++i && !finished) 
    { 
    } 
    std::cout << "i=" << i << " flag=" << std::boolalpha << bool(finished) << "\n"; 
} 
+2

また、コマンドラインから 'ulimit -t 'を使ってこれを行うことができます。 – SoapBox

+2

シグナルハンドラ内でホワイトリスト形式の変数を変更することしか許されていないと思いますが、 'bool'がリストにあるかどうかはわかりません。しかし、 'sig_atomic_t'はその目的のために作られたようです。 –

+0

あなたは正しいです:シグナルハンドラで 'sig_atomic_t'への変更だけが保証されています。私は対応してコードを調整しました。ありがとうございました! –