fork 和 vfork 使用的注意事项和 system() 函数的替代

在Linux编程中,咱们常常使用 Fork()。然而很多状况下,fork是有危险的。可是又不能简单使用vfork替换就成了。这个笔记说明了二者使用的一些注意点。
本文地址:https://segmentfault.com/a/11...html


Reference:

fork与vfork的区别
vfork,fork,exec函数的区别
C语言函数 atexit execl execlp ……(太长了)编程

vfork() 与 fork()

pid_t vfork(void);

vfork的做用

函数vfork的做用是建立一个子进程,而这个子进程的做用是用于调用exec(),从而再执行一个新进程(每每是用来执行其它的程序)segmentfault

代码空间

在程序的执行效果上,fork会将父进程的地址空间复制一份,,可是vfork并非这么作,而是 vfork 以后的子进程,在调用 exec 或 exit 以前,在父进程的空间中执行函数

执行顺序

vfork保证子进程优先执行到execexit以前,父进程都不会被调度。
fork父子进程执行顺序不肯定。.net

所以,执行了vfork以后,子进程请当即执行 exec,而不要再执行一次 fork,不然就可能致使死锁。
或者这么说,若是在execexit以前依赖于父进程的进一步动做,就会致使死锁code

另外请留意,exec并非建立进程,只是用新程序替换了当前进程的上下文。orm

system()的替代

频繁调用system()以后,有可能卡死不返回,就是由于出现了这个状况。system是基于fork实现的,调用后父子进程调用顺序不必定,可能致使system()调用死锁。
这个危险的函数,如今咱们已经禁用了。换成使用vfork或者是__libc_fork实现,代码以下(这份是我本身写的,不是公司的代码,不过原理上差很少):htm

#define _CMD_LEN    (256)

static int _system (char *cmd);
int AMCSystemCmd (const char *format, ...)
{
    char cmdBuff[_CMD_LEN];
    va_list vaList;
    
    va_start (vaList, format);
    vsnprintf ((char *)cmdBuff, sizeof(cmdBuff), format, vaList);
    va_end (vaList);
    
    return _system ((char *)cmdBuff);
}
extern int __libc_fork (void);
static int _system (char *command)
{
    int pid = 0;
    int status = 0;
    char *argv[4];
    extern char **environ;
    
    if (NULL == command) {
        return -1;
    }
    
    pid = __libc_fork();        /* vfork() also works */
    if (pid < 0) {
        return -1;
    }
    if (0 == pid) {             /* child process */
        _close_all_fds();       /* 这是我本身写的一个函数,用来关闭全部继承的文件描述符。可不用 */
        argv[0] = "sh";
        argv[1] = "-c";
        argv[2] = command;
        argv[3] = NULL;
        
        execve ("/bin/sh", argv, environ);    /* execve() also an implementation of exec() */
        exit (127);
    }
    
    // else
    /* wait for child process to start */
    do
    {
        if (waitpid (pid, &status, 0) < 0) {
            if (errno != EINTR) {
                return -1;
            }
            else {
                return status;
            }
        }
    } while (1);
    
    return 0;
}

使用时用AMCSystemCmd()直接替代system便可,还支持动态参数列表呢blog