2017-12-01 4 views
1

私の最初のスタックオーバーフローポスト、私はサイトのlurkerですが、私は本当に自分自身のいくつかの質問をし始めたいと思っていました!指定されていない予期しない関数呼び出しを引き起こすC fork()

私は、unistd.hライブラリを使ってfork()システムコールについて学んでいます。私は何を学んでいるのか試してみたい。 UNIXでの簡単なプロセス作成の例については、教科書に従ってきました。私はOSXでこれをやっています。私はシェルを作成するタスクを設定されているので、私はシェルを構築するための完全な答えを与えたくないので、なぜプログラム全体ではなく、この特定のシステムコールについて尋ねています。

コードは完全に正常に動作し、期待される出力が得られます。

これは細かい作業のコードは次のとおりです。

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

int main() { 
    pid_t pid; 
    pid = fork(); 
    if(pid == 0){ 
     printf("\nI'm the child\n\n"); 
    } 
    else if(pid > 0){ 
     printf("\nI'm the parent, child has pid: [%d]\n", pid); 
    } 
    else{ 
     printf("ERROR"); 
    } 
    return 0; 
} 

私の問題は、私は私のシェルプログラムでこれを入れたとき、それは私が、オンラインフォーク爆弾を発見したものから、原因となっていることです。

このプロセスを作成する関数は、 'test'コマンドで呼び出されます。関数を実行すると、スタンドアロン版と同じ出力が得られますが、次に移動して終了すると、無限ループでそのテスト関数を再度呼び出すように見えます。コンピュータが遅れているので、私はプロセスを殺すことができません。なぜなら、一連のプロセスが作成され、コンピュータを再起動する必要があるからです。私はこれを数回やりました。実行するたびに再起動を実行する必要があるため、テストが不可能になってきています。

私は、終了コマンドを終了することを期待しているwhileループを持っています。コードは以下のように自明でなければなりません。私はwait()システムコールを使うべきだと考えている研究から、これらのコンセプトをテストしようとしていますが、私のコードがこれを引き起こしている理由を理解したいと思います。

完全なプログラム:

main.cの

#include "shell.h" 

int main() { 
    clear(); 
    printf("Jack's Shell\n"); 
    shellLoop(); 
    clear(); 
    return 0; 
} 

shell.c

#include "shell.h" 

void shellLoop(){ 
    char command[MAX_STRING_LEN]; 
    int exit = 1; 
    while (exit != 0){ 
     printf("\njackdewinter$ "); 
     scanf("%s", &command); 
     exit = commandInterpreter(command); 
    } 

} 

int commandInterpreter(char * cmd){ 
    char message[MAX_STRING_LEN]; 
    if(strcmp(cmd, "exit") == 0){ /* Best way to test strings (Not just characters.) */ 
     return 0; 
    } 
    else if(strcmp(cmd, "info") == 0){ 
     info(); 
     return 1; 
    } 
    else if(strcmp(cmd, "pwd") == 0){ 
     shellMessage("Call PWD"); 
     return 1; 
    } 
    else if(strcmp(cmd, "cd") == 0){ 
     shellMessage("Call CD"); 
     return 1; 
    } 
    else if(strcmp(cmd, "test") == 0){ 
     shellMessage("Test Called."); 
     test(); 
     return 1; 
    } 
    else if(strcmp(cmd, "help") == 0){ 
     shellMessage("Call HELP"); 
     return 1; 
    } 
    else{ 
     shellMessage("Incorrect command entered.\nType help for assistance and a list of commands."); 
     return 1; 
    } 
} 

void info(){ 
    shellMessage("This shell was created by Jack Dewinter"); 
} 

void test(){ 
    pid_t pid; 
    pid = fork(); 
    if(pid == 0){ 
     printf("Child\n"); 
    } 
    else if(pid > 0){ 
     printf("I'm the parent, child has pid %d\n", pid); 
    } 
    else{ 
     printf("ERROR"); 
    } 
} 

void shellMessage(char * message){ /* Using this for consistent shell messages. */ 
    printf("\n%s\n", message); 
} 

shell.h

#define MAX_STRING_LEN 80 

#define clear() printf("\033[H\033[J") /* Terminal escape codes for clearing the console */ 

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

void shellLoop(); 
int commandInterpreter(char * cmd); 
void info(); 
void test(); 
void shellMessage(char * message); 

ご協力いただきありがとうございます、ありがとうございます!

+1

これはフォークの爆弾ではなく、単なるバグです。終了したら、子プロセスは 'exit()'する必要があります。私。 'if(pid == 0) 'ブロックの中にあります。結局、フォークされたプロセスは終了するはずです。私が見ていることから、親がそれをいつでも気にする理由はありませんが、それでもやはりそうするべきです。また、コマンドインタープリタとその選択のメニューに戻ることもあります。 – WhozCraig

+0

子供と親の両方があなたのループに戻ります。出口もない。今は2つのプロセスがあります。 stdinに何かを入力すると、それは子供に行きます。しかし、子供が出ると、親はまだ走っていて、stdinからの読み込みを待っています。テストを複数回実行すると、入力待ちのインスタンスが複数存在します。私は爆弾を作成するループが表示されません。 – HardcoreHenry

+1

このコードにバッファオーバーフローがあります。 'scanf("%s "、&command)'を 'scanf("%80s "、&command)'に置き換えるか、代わりに 'fgets'を使うべきです。 –

答えて

6

forkで新しいプロセスを作成すると、子プロセスはフォークのポイントから続けられます。だからあなたの子供は "子供"、を印刷しますが、それからtestに戻ります。したがって、親だけが実行しなければならないコードを実行し続けます。

mainからすぐに戻り、子プロセスを終了させるため、小さなコードにはこれが表示されません。

あなたは、その部分が終わった後に子供を退室させる必要があります。また、子供のために親はwaitになる必要があります。ゾンビのプロセスが残っていないようにしてください。あなたはライブラリ関数exitをマスキングしているよう

void test(){ 
    pid_t pid; 
    pid = fork(); 
    if(pid == 0){ 
     printf("Child\n"); 
     _exit(0); // exit child; use _exit instead of exit 
        //to prevent atexit handlers from being called 
    } 
    else if(pid > 0){ 
     printf("I'm the parent, child has pid %d\n", pid); 
     // wait for child to finish 
     wait(NULL); 
    } 
    else{ 
     printf("ERROR"); 
    } 
} 

また、shellLoopに、何か他のものに変数exitの名前を変更します。

+0

ありがとうございます、これで問題は解決しました。私のコンピュータは、プログラムを実行しようとすると、もはや中断されません。待ち(NULL)は実行を継続することもできます。それ以外の場合は中断します。 – jackdewinter

+0

終了変数のヒントもありがとう、私はこの本を読んでいる間にこれをすばやく書きました。私はこれを完全に書き直すつもりです。多くの人がこれらの種類のプログラムにステータス変数を使用しています。 – jackdewinter

3

あなたが作成している子供は、彼の父親のようにループし、各ループに新しいプロセスを持たせることになります。 fork:正確なプロセスイメージを作成します。あなたは何ができるか

は次のとおりです。 1-のprintf(「子\ nの」)の後に、子供(子供が終了するのを、すなわち父が待つ)

2-もしくはただの出口を(追加)に参加します;それは子供を終わらせ、父親を走らせ続ける。

+0

ありがとうございます。私はそれらが両方とも子供が作成された時点から実行されていることを理解していますが、何らかの理由で 'test'がコマンドとして入力されていなければループはテスト関数を再度呼び出すべきではありません。 – jackdewinter

関連する問題