Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/151.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ Linux、waitpid、WNOHANG和僵尸_C++_C_Fork_Wait_Waitpid - Fatal编程技术网

C++ Linux、waitpid、WNOHANG和僵尸

C++ Linux、waitpid、WNOHANG和僵尸,c++,c,fork,wait,waitpid,C++,C,Fork,Wait,Waitpid,我需要能够: 分叉一个进程并使其执行(我做到了) 检查子进程execvp是否成功(不知道如何成功) 检查子进程是否已完成(存在问题) 我正在分岔一个过程,我没有任何方法来检查孩子的execvp是否有效或失败。如果它失败了,我需要知道它失败了。目前我正在使用 -1 != waitpid( pid, &status, WNOHANG ) 但是,如果pid进程的execv失败,waitpid似乎不会返回-1 我怎么能检查呢?我读了waitpid手册页,但我不清楚;也许我的英语不够好 编辑:为

我需要能够:

  • 分叉一个进程并使其执行(我做到了)
  • 检查子进程execvp是否成功(不知道如何成功)
  • 检查子进程是否已完成(存在问题)
  • 我正在分岔一个过程,我没有任何方法来检查孩子的execvp是否有效或失败。如果它失败了,我需要知道它失败了。目前我正在使用

    -1 != waitpid( pid, &status, WNOHANG )
    
    但是,如果pid进程的execv失败,waitpid似乎不会返回-1

    我怎么能检查呢?我读了waitpid手册页,但我不清楚;也许我的英语不够好

    编辑:为了解释更多内容:
    我正在为家庭作业建造自己的终端。我需要输入一个命令字符串,比如“ls”,然后我必须执行该命令。
    在子fork之后,子对象调用execvp以执行命令(在我解析字符串之后),父对象需要检查命令末尾是否有“&”。
    如果命令末尾不存在符号“&”,则父级需要等待子级执行


    所以我需要知道execvp是否失败了。如果没有失败,则父级使用waitpid等待子级完成执行。如果失败,则父进程将不等待子进程。

    如果执行成功,则不应返回exec调用,因为它将用另一个进程映像替换当前进程映像,因此如果执行成功,则表示发生了错误:

    execvp(...);
    /* exec failed and you should exit the
       child process here with an error */
    exit(errno);
    
    要让父进程知道执行是否失败,应读取子进程的状态:

    waitpid(pid, &status, WNOHANG);
    
    然后使用手册页中的
    WEXITSTATUS(status)
    宏:

    WEXITSTATUS(status)返回子级的退出状态这个 由状态参数的最低有效8位组成 在对exit(3)或_exit(2)的调用中指定的子级,或作为main()中return语句的参数指定的子级。

    注意,最后一条语句的意思是,如果
    exec
    成功并运行该命令,您将获得该命令的
    main()
    函数的退出状态,换句话说您无法可靠地区分失败的
    exec
    和失败的命令之间的区别,因此这取决于这对您是否重要

    另一个问题:

    如果命令末尾不存在符号“&”,则 父级需要等待子级执行

    您需要在程序中的某个点调用子进程上的
    wait()
    ,而不管
    &
    如何,以避免使子进程处于僵死状态

    注意:当您使用
    WNOHANG
    时,意味着如果没有进程更改其状态,则
    waitpid()
    将立即返回,即它不会阻塞,我假设您知道,否则使用
    wait()
    或调用
    waitpid()
    作为主循环的一部分。

    对于#2,一个常见的解决方案是在fork()之前打开一个管道,然后在exec之后的子循环中写入它。在父级中,成功读取意味着exec失败;读取失败意味着exec成功,而写入从未发生

    // ignoring all errors except from execvp...
    int execpipe[2];
    pipe(execpipe);
    fcntl(execpipe[1], F_SETFD, fcntl(execpipe[1], F_GETFD) | FD_CLOEXEC);
    if(fork() == 0)
    {
        close(execpipe[0]);
        execvp(...); // on success, never returns
        write(execpipe[1], &errno, sizeof(errno));
        // doesn't matter what you exit with
        _exit(0);
    }
    else
    {
        close(execpipe[1]);
        int childErrno;
        if(read(execpipe[0], &childErrno, sizeof(childErrno)) == sizeof(childErrno))
        {
            // exec failed, now we have the child's errno value
            // e.g. ENOENT
        }
    }
    
    这让父级明确地知道exec是否成功,如果失败,errno值作为副产品是什么

    如果exec成功,子进程可能仍然会失败,并显示退出代码,使用
    WEXITSTATUS
    宏检查状态也会给出该条件


    注意:使用
    WNOHANG
    标志调用
    waitpid
    是非阻塞的,您可能需要轮询流程,直到返回有效的pid。

    有史以来最好的问题标题。这里有几个因素可能会影响您的解决方案:您的
    execvp
    将您的流程带入了什么?你有能力编辑吗?在孩子退出之前不知道execvp是否失败可以吗?如果您发布更详细的问题陈述,我们可能会给出更好的建议。如果出现上述故障,您不能从孩子向家长发送信号吗?在这种情况下,您实际上不需要知道execvp是否成功。您需要做的就是决定是否使用
    WNOHANG
    进行
    waitpid
    。如果有&,则使用它。否则,请使用一些结构来监视后台任务。实际上,请查看我给出的答案-它提供了相当不错的代码解决方案。我认为这个问题的困难部分是让父进程知道execvp失败。因为OP不想澄清,我将扮演魔鬼代言人:如果我需要确保孩子在发送信号或其他控制信息之前正确地执行了
    execvp
    ed,因此不能等待它真正退出呢?哦,如果你的
    waitpid
    execvp
    失败之前执行并返回,这将是一个假阳性。@FrankieTheKneeMan但OP的第三个问题是检查它是否完成,这意味着他正在等待子进程并且不想与它说话:)@FrankieTheKneeMan和
    waitpid
    不会返回,除非孩子的状态为changes@Ryan-Callhoun,谢谢,但是阅读会阻止家长,不是吗?如果执行成功,我需要家长不要等待。我编辑了我的帖子来澄清。谢谢@m1o2:注意
    FD\u CLOEXEC
    。当
    execv*
    成功时,子级上的管道关闭。读取将为EOF返回0。如果可用,将
    pipe2
    O_CLOEXEC
    一起使用,而不是
    pipe
    后跟
    fcntl
    。它不仅效率更高,而且还通过打开管道自动设置close-on-exec标志,因此在其他线程也可能运行外部命令的情况下,它可以安全地用于多线程。到目前为止,
    pipe2
    是一个扩展,但它已经被接受包含在下一版本的POSIX中。