首页 > 解决方案 > 即使子进程已死,waitpid 也会挂起

问题描述

我有以下功能:

int run_func(command history[MAX_INPUT_SIZE], char** args, int capacity) {
    int need_to_wait = 1;
    int i = 0;
    char* arg = args[0];
    int status;
    while (arg != NULL) {
        if (strcmp(arg, "&") == 0) {
            need_to_wait = 0;
            break;
        }
        arg = args[i++];
    }
    pid_t wait_pid;
    pid_t pid = fork();
    int res;
    if (pid == 0) {
        res = execvp(args[0], args);
        if (res == -1) {
            printf("exec failed\n");
            fflush(stdout);
            return 0;
        }
    } else if (pid < 0) {
        printf("fork failed\n");
        fflush(stdout);
        return 0;
    } else {
        if (need_to_wait){
            do {
                wait_pid = waitpid(pid, &status, 0);
            } while(!WIFEXITED(status) && !WIFSIGNALED(status));
        }
        history[capacity - 1].pid = pid;
    }
    return 1;
}

我遇到的问题是,当我从终端收到来自用户的无效命令(例如“hello”)时,底部的 while 循环会挂起并且不会停止,直到我再次按 Enter 键。这个函数是从另一个接收用户输入的函数调用的。

标签: cshell

解决方案


将评论复制到答案中。

附带问题:

  • 错误消息应该打印到stderr,而不是stdout
  • 无需保存或测试返回值execvp()——如果返回,则失败;如果成功,则不会返回。

主要观察:

  • 您几乎肯定应该在错误处理代码中使用exit()or_exit()而不是. 当命令失败(?)时,您最终会运行两个进程 - 一个来自失败的进程,一个是父进程。这很容易混淆一切,因为您有两个进程试图同时读取终端。return 0;execvp()helloexecvp()

推荐阅读