execv 和 fork:通知父进程子进程执行文件失败

psi*_*tte 5 c fork execv waitpid

主进程如何知道子进程执行文件失败(例如没有这样的文件或目录)?例如,在下面的代码中,我们怎样才能让 run() 返回 0 以外的值呢?谢谢!

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

enum ErrorType { noError, immediateFailure, returnFailure, forkFailure };

using namespace std;

int run(void)
{
    int error = noError;
    //char proc[] = "/bin/uname";
    char proc[] = "/usr/bin/Idontexist";
    char *const params[] = {proc, NULL};

    pid_t pid = fork();

    printf("pid = %d\n",pid);

    if (pid == 0)
    {
        if ( execv(proc,params)==-1 )
        {
            error = immediateFailure;
        }
        printf("child: error = %d\n",error);
    }
    else if (pid > 0)
    {
        /*  This is the parent process
         *  incase you want to do something
         *  like wait for the child process to finish
         */
        int waitError;
        waitpid(pid, &waitError, 0);

        if ( waitError )
            error = returnFailure;

        printf("parent: error = %d, waitError = %d\n",error,waitError);
    }
    else
    {
        error = forkFailure;
    }

    return error;
}

int main(void)
{
    printf("run() = %d\n",run());

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

pid = 4286
pid = 0
child: error = 1
run() = 1
parent: error = 0, waitError = 0
run() = 0
Run Code Online (Sandbox Code Playgroud)

Ant*_*ala 1

main您需要从或 中返回错误代码exit()以及值。现在,您在所有情况下都是returnfrom 0main这将是父级从 收到的子级的退出代码waitpid

_exit(error)最好的解决方法是在子进程中添加:

printf("child: error = %d\n",error);
_exit(error);
Run Code Online (Sandbox Code Playgroud)

无论如何,请使用整数常量而不是随机枚举常量 enum。1 和 2 是许多 unix 命令的常见返回值,其中 1 表示命令不成功(例如grep没有找到任何匹配项),2+ 表示命令确实失败(参数错误等)。

bashzsh以及其他 shell 用作127退出代码来指示命令未找到/无法运行;因此建议:

#define COMMAND_NOT_RUNNABLE 127

/* ... */

execv(proc, params);  // exec never returns if successful.
perror(proc);
_exit(COMMAND_NOT_RUNNABLE);
Run Code Online (Sandbox Code Playgroud)

在子进程中使用的原因_exit是它不会刷新 stdio 缓冲区(这也存在于父进程中)并且它不会运行钩子atexit。(感谢安德鲁·亨利

  • 有点老了,但是在 `fork()` 失败的 `exec()` 之后调用 `exit()` 可能会导致严重的问题。`exit()` 将刷新所有输出 `FILE *` 流以及它们保存的从父进程地址空间继承的数据。如果父进程是多线程的,那么在调用“exec()”时,如果任何流被不同的线程锁定,则可能会发生死锁。由 `atexit()` 注册的函数也会被调用。如果链接任何 C++ 代码,将调用静态析构函数。`_exit()` 更安全。 (2认同)