C fork()导致未指定的意外函数调用

时间:2017-12-01 21:13:18

标签: c linux shell fork system-calls

我的第一个Stack Overflow帖子,我是该网站上的潜伏者,但我真的想开始问我自己的一些问题!

我正在使用unistd.h库了解fork()系统调用。我想测试一下我学习的内容。我已经在教科书中找到了关于在UNIX中创建简单进程的示例。我在OSX上这样做。我已经设置了一个创建shell的任务,我不想给出构建shell的完整答案,因此我为什么要询问这个特定的系统调用,而不是整个程序。

代码本身运行完全正常,并提供预期的输出。

这是正常运行的代码:

#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;
}

我的问题是,当我把它放在我的shell程序中时,它引起了我在网上找到的一个叉炸弹。

使用命令&#39; test&#39;调用创建此过程的函数。当我运行该函数时,它提供与独立版本相同的输出,但是当我继续前进并退出时,似乎在无限循环中再次调用该测试函数。然后,我无法终止进程,因为我的计算机已经停滞不前,显然是因为正在创建一堆进程而我必须重新启动计算机。我现在已经完成了几次,因为每次运行都需要重新启动,所以无法进行测试。

我有一个期望退出命令结束的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);

非常感谢任何帮助,谢谢!

2 个答案:

答案 0 :(得分:6)

使用fork创建新进程时,子进程将从fork的位置继续。因此,您的孩子打印“儿童”,,然后从test 返回。因此它继续运行只应运行父代码的代码。

您在较小的代码段中没有看到这一点,因为您立即从main返回,导致子进程退出。

你需要让孩子在完成它之后退出。此外,父母应该为孩子wait,以便您不会留下僵尸进程。

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时,将变量exit重命名为其他内容。

答案 1 :(得分:3)

您正在创建的孩子将像他父亲一样循环,并且您将每个循环都有一个新过程。 fork:创建精确的过程映像。

你能做的是: 1-加入孩子(即父亲等待孩子完成)

2-或者只是在printf之后添加一个exit()(&#34; Child \ n&#34;);这将结束孩子,并保持父亲的运行。