2016-10-13 11 views
41

私はC++プログラムを開発しています。関数やスクリプトなどを使用してプログラムを再起動すると便利です。大きなプログラムなので、すべての変数を手動で再起動すると時間がかかります...プログラム内部からプログラムを再起動することはできますか?

これを達成する方法があるのか​​、それが可能なのかわかりません。

int main() 
{ 
    while (true) 
    { 
     //.... Program.... 
    } 
} 

あなたは、再起動ループ内continue;を呼び出して、あなたのプログラムを終了する必要があるたびに、break;を使用します。

+37

あなたがしていることは、あなたのコードで 'main()'を呼ばないでください。 – NathanOliver

+14

"すべての変数を手動で再起動する" Wut? – Treycos

+5

ループを使用することを検討しましたか? –

答えて

53

プログラム全体を再起動する必要がある場合(つまり、「閉じる」と「開く」)、「適切な」方法は、メインプログラムを再起動する唯一の目的のために別のプログラムを持つことです。 AFAIKでは、このように自動更新機能を備えたアプリケーションが数多く用意されています。したがって、メインプログラムを再起動する必要がある場合は、単に「再起動」を呼び出して終了してください。

+0

それでは、お互いに電話をかけて再起動するときに終了する2つのプログラムがあれば十分でしょうか? –

+6

彼らはお互いを呼びません。呼び出し元は基本的に2番目を呼び出すループであり、終了するのを待ってから再び呼び出します。 「本当の」プログラムは呼び出し元について何も知らない。それだけで終了します。 – chepner

+3

ワイトドッグが再開したいかどうかは、作業者が終了コードで示すことができます。 –

6

はおそらくループを必要としています。

+1

誰にお勧めしていませんか? – StoryTeller

+0

リンクがありますか?推論は読むのがよいでしょう。あなたの答えを高めるかもしれません。 – StoryTeller

+0

それは1人の意見で、1人の男です。その意見に基づいてこれらの機能が「推奨されない」と主張することは役に立たない。個人的に私はピーターとは反対ですが、彼の意見は有効です。それだけではありません。 –

42

あなたのmain関数内でループを使用することができます。

int main() 
{ 
    while(!i_want_to_exit_now) { 
     // code 
    } 
} 

それとも、あなたが実際にプログラムを再起動したい場合は、ハーネスからそれを実行します。

42はリターンです
program "[email protected]" 
while [ $? -e 42 ]; do 
    program "[email protected]" 
done 

コードは "再起動してください"を意味します。

は次に、プログラム内部であなたのrestart関数は次のようになります。

void restart() { 
    std::exit(42); 
} 
+2

プログラムがうまく書かれていないと、最初の解決策がうまくいきません。たとえば、メモリリークが含まれている場合、単純にループを通過することで解放されません。しかし、あなたが提供したもう一つのソリューションは、この種の問題さえも処理します。 –

+16

@HumamHelfawiプログラムにメモリリークがある場合は、プログラムがループで実行されているかどうかに関わらず、何らかの方法で修正する必要があります。同じロジックを使って、最初のアプローチはうまくいかないと言うことができます。プログラムにUBがある場合、それはUBを何度か持っているからです。 – user463035818

+3

@ tobi303いいえ、それは良くありません。しかし、「プログラムを再開する」という言葉は、「すべてのガーベージを清める」という意味、つまり「すべてをクリアして新鮮にする」という意味です。そのため、漏れのクリーニングはその一部であると考えられます...とにかく、私は誰も漏れを残さず、それを解決するための再起動方法を使用しています。私はちょうどそれが言及する価値があると思った –

12

これは非常にOS固有の問題です。 Windowsでは、Application Restart APIまたはMFC Restart Managerを使用できます。あなたはLinuxでこれを行うことができますexec()

ほとんどの場合、より良い解決策があります。他の答えで示唆されているように、ループを使うほうが良いでしょう。それは例この種を除いて、一般的にひどいですので

15
Uniciesで

、またはどこか他のあなたはexecve持っており、それがthe man page specifiesのように動作し、あなただけ... は、atoiを使用するための私を殺すことができます。

#include <unistd.h> 
#include <stdio.h> 
#include <stdlib.h> 

int main (int argc, char** argv) { 

    (void) argc; 

    printf("arg: %s\n", argv[1]); 
    int count = atoi(argv[1]); 

    if (getchar() == 'y') { 

    ++count; 

    char buf[20]; 
    sprintf(buf, "%d", count); 

    char* newargv[3]; 
    newargv[0] = argv[0]; 
    newargv[1] = buf; 
    newargv[2] = NULL; 

    execve(argv[0], newargv, NULL); 
    } 

    return count; 
} 

例:

$ ./res 1 
arg: 1 
y 
arg: 2 
y 
arg: 3 
y 
arg: 4 
y 
arg: 5 
y 
arg: 6 
y 
arg: 7 
n 

7 | $ 

(7戻りコードでした)。

再帰的にも明示的にループすることなく、自分自身を呼び出すだけで、自身のメモリ空間を新しいバージョンのものに置き換えます。

このようにして、スタックは再オーバーフローすることはありません。以前のすべての変数は再呼び出しと同様に再宣言されますが、getchar呼び出しは100%CPU使用率を防ぎます。

自己更新バイナリの場合、実行時にバイナリ全体(少なくともUNIXについてはわかりません)がメモリにコピーされるため、ファイルがディスク上で変更されるとexecve(argv[0], ...コールの前に、同じ古いものではなく、ディスク上に見つかった新しいバイナリが代わりに実行されます。

として@CarstenSとによりUnixのは、オープン・ファイル記述子がfork/exec渡って保持されているように設計されたユニークな方法に、コメントで指摘@bishop、および全体でオープンファイルディスクリプタを漏洩しないようにするために、結果として、 execveに電話する場合は、execveより前に閉じるか、e,FD_CLOEXEC/O_CLOEXECで開きます。詳細はDan Walsh's blogで確認できます。

+3

取得されている可能性のあるリソースについて教えてください。 –

+1

@CarstenSおそらく、彼らは流出するでしょう。 http://danwalsh.livejournal.com/53603.html – bishop

+0

@CarstenSを参照してください良い質問、私はいくつかのテストを行う必要があります。私の感心しているのは、プログラムメモリ*の残りの部分とともにヒープが消えてしまい、 "新しい"ヒープで上書きされるので、プログラムが終了したときと同じように破棄されます。 – cat

1

プログラムを再起動することによって何を意味するかに応じて、私はいくつかの簡単な解決策を見ることができます。

1つは、プログラム全体をいくつかの「プログラム」クラスに埋め込むことです。これは基本的に、適切なプログラムを持つループを提供します。プログラムを再起動する必要があるときは、静的パブリックメソッド "Restart"を呼び出してループを再開します。

また、プログラムを再起動して終了するシステム固有の呼び出しを試みることもできます。 他の答えで示唆されているように、この唯一の目的のためにラッパープログラムを作成することもできます(終了または再起動するかどうかを知るための戻りコードを確認することもできます)。

他の簡単なオプションはgotoです。人々はそれについて言及しても私を憎むだろうが、それに直面してみましょう:我々は、美しい定型文を使用しないで簡単なプログラムを作りたいと思います。 Goto going back guarantees destructionのように、先頭にラベルが付いたプログラムを作成し、ちょうど先頭に戻る「再起動」機能をいくつか作成することができます。

どのようなオプションを選択しても、それをうまく文書化するので、他の人(またはあなたの将来)は1つ少ないWTFを使用します。

PS。 alainで述べたように、gotoはグローバルオブジェクトも静的オブジェクトも破壊することはありませんが、クラスを囲む場合も同様です。したがって、現在のプログラムの代わりに新しいプログラムを開始することを含まないアプローチは、グローバル/静的変数の使用を控えるか、またはそれらを再設定するための適切な処置をとるべきです(静的/再起動ルーチンを変更する必要があります)。

+2

'goto'はグローバルオブジェクトと静的オブジェクトを破壊しません。 – alain

8

すべての状態がグローバルであるように、これは間違ったアプローチのように聞こえるので、すべての変数を手動でリセットする以外はすべてのプログラムを再起動するだけです。

代わりに、あなたの状態はオブジェクト(クラス型のものなど)で保持する必要があります。あなたはいつでも自由にこれらのオブジェクトを作成して破壊することができます。新しいオブジェクトはそれぞれ、「デフォルト」の値を持つ新しい状態になります。

C++と戦わないでください。これを使って!私はリアルタイムシステムを開発する場合

4

は私のアプローチは、通常、「派生メイン()」私は)(本当のメインから呼び出されるすべてのコードを記述する場合は、のようなもの:

main.cppにプログラム:

int main (int argc, char *argv[]) 
{ 
    while (true) 
    { 
     if (programMain(argc, argv) == 1) 
      break; 
    } 
} 

プログラマ。すべてのコードが書かれているCPP、:

int programMain(int argc, char *argv[]) 
{ 
    // Do whatever - the main logic goes here 

    // When you need to restart the program, call 
    return 0; 

    // When you need to exit the program, call 
    return 1; 
} 

そのようにして、我々はプログラムが再起動されるプログラムを終了することを決定するたびに。

詳細:すべての変数、グローバルおよびロジックは、programMain()の内部に書き込まれていなければなりません。"main()"の中には何も書き込まれていません。

このアプローチは、LinuxシステムとWindowsシステムの両方で機能します。

+0

これはループバックしてprogramMainをもう一度呼び出しませんか?外側whileループを壊すには何かが必要です。私はC++の人ではありませんが、特に1つのリターンコードでそれを行った場合は驚くでしょう。 – Alex

+0

はい、考えてみましょう。もう一度 'programMain()'を呼び出して、ロジック全体実際、 'return 1'はループを終了することができます。編集しました.... – Mendes

+0

今はっきりしています。私は個人的には、完全に/きれいに再起動する別個のミニプログラムを持っているアプローチをまだ好むでしょうが... – Alex

2

正しい質問をするためにコーディングについて十分な知識がないので、間違った質問をしているように聞こえます。

あなたが尋ねるように聞こえるように聞こえているのは、不在着信時にループを初期状態に戻して、呼び出し/位置シーケンス全体を再起動するコードの書き方です。その場合は、state machineを使用する必要があります。それが何であるかを見て、それを書く方法。これは重要なソフトウェアコンセプトであり、教師が自分の仕事にうってつけだったらそれを知るべきです。

あなたのプログラムがすべての変数を初期化するために5秒かかる場合は、再起動すると5秒かかることになります。あなたはそれをショートカットすることはできません。だから、それはあなたがあなたが望んでいない振る舞いを正確に得るので、が実際にあなたのプログラムを殺して再起動したいことが明らかであるはずです。ステートマシンを使用すると、コールドスタートのための1つの初期化状態を持つことができます。ここでは、システムがオンになったばかりで、ウォームリスタートの2番目の初期化状態です。

ああ、6スレッドはあまり多くありません! :)

+0

もちろん、私は多くのことを学び、改善する必要があります。私は "全体"呼び出し/位置のシーケンスを再開したくない、私は全体のアプリケーション、7ファイル、センサーバイアスを再起動したい...これは私が必要とする動作であるため、私はプログラムを再起動したい。ウォームリスタートを行うと、コードと労力がかかりすぎて、何も手に入れません。コードが複雑になります。 –

+0

ファイルを閉じてから再度開き、変数を再初期化しますか?次に、不在着信後にファイルを閉じます。ループを回して初期化の作業をやり直してください。私は失礼しようとしているわけではありませんが、アプリケーションの再起動は単純なループの妥当な代替手段ではありません。これがユニプロジェクトの場合は、技術的能力が不足していると***評価されます。私は失礼にしようとしているわけではありません。私はあなたに良い成績をもたらす方向にあなたを指摘しようとしています。 :) – Graham

関連する問題