【问题标题】:Child process not exiting with fork()子进程未使用 fork() 退出
【发布时间】:2019-02-25 10:01:57
【问题描述】:

我正在用 C 语言创建一个简单的 Linux 命令 shell。我无法理解我的代码出现问题的地方。 “commands”是我希望作为一个父进程的子进程同时执行的 Linux 命令字符串列表。全部执行完毕后,我希望父级退出该函数。但是,当我调用 exit(0) 时,for 循环继续并再次解析当前命令,导致 args 在 execvp 中再次执行。我在这里正确使用 fork() 和 wait() 吗?我也尝试过使用 waitpid(),但没有成功。

void executeShell(char** commands){
    char **arr = commands;
    char *c;
    pid_t pid, wpid;
    int status = 0;

    for (c = *arr; c; c=*++arr){
        // printf("%d-\n", strcmp(command, "exit"));

        if (strcmp(c, "exit") == 0){
            EXIT = 1;
            return;
        }

        printf("Running command \'%s\'...\n", c);

        char** args = parseStringToTokenArray(c, " ");
        free(args);

        /* fork and execute the command */
        pid = fork();
        if(pid < 0){
            perror("fork() error\n");
            return;
        }
        /* child process executes command */
        else if (pid == 0){
            /* 'cd' is not a part of /bin library so handle it manually */
            if (strcmp(args[0], "cd") == 0){
                changeDirectory(args[1]);
            }
            else if (strcmp(args[0], "sdir") == 0){
                searchDirectory(args[1]);
            }else{
                /* parse commands with arguments */
                execvp(args[0], args);//execute the command
            }
            exit(0);// <-----command is finished, so why no exit?
        }                                     
    }                                          
    /* wait for children to complete */          
    while((wpid = wait(&status)) > 0);         
}                                               

【问题讨论】:

  • 父亲执行的代码块在哪里?
  • 正如@nissimabehcera 提到的,看起来父亲的执行仍在循环中。
  • 为什么你在创建它之后就free(args);?难道你不应该等到你使用它(或不再需要它)之后吗?
  • 你小时候要分叉什么命令?它们是完成还是无限期运行?

标签: c fork exec wait waitpid


【解决方案1】:

如果execvp成功,整个子进程地址空间被execvp()调用的程序替换。这意味着exit(0) 只会在您的两个特殊情况下被调用,即cdsdir。就您的代码而言,execvp() 不应返回,除非出现错误。

另一个问题是您在分配args 后立即释放它,然后继续在您的子进程中使用它。这是未定义的行为。

我看到您的wait 代码的唯一问题是,如果任何子级阻塞等待用户输入,则父级将阻塞等待子级退出。

cd 代码对除执行它的子进程之外的任何进程都没有影响。父级的当前目录不受影响。正如您在 cmets 中所述,这可以通过在父级中处理 cd 而无需分叉来解决。

【讨论】:

  • 问题是使用前的 free() 取消分配。此外,我不得不将“cd”案例移到循环之外,因为当调用 exit(0) 时,更新的工作目录将会丢失。哇,这么简单的错误就引起这么大的头痛!谢谢你:)
  • 是的,我与自己争论过是否要提及cd 问题。为了完整起见,我可能会将其添加到答案中。
  • @M.Rosenlof:回复。简单的错误 -> 严重的头痛:那是 undefined behavior 给你的!
猜你喜欢
  • 1970-01-01
  • 2017-03-04
  • 1970-01-01
  • 2012-01-14
  • 1970-01-01
  • 2014-01-21
  • 2015-01-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多