#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
1、上述exec系列函数底层都是通过execve系统调用实现:
execve() executes the program pointed to by filename. filename must be either a binary executable, or a script starting with a line of the form
2、带L的exec函数:execl,execlp,execle,表示后边的参数以可变参数的形式给出且都以一个空指针结束。
3、带 p 的exec函数:execlp,execvp,表示第一个参数path不用输入完整路径,只有给出命令名即可,它会在环境变量PATH当中查找命令
4、vfork保证子进程先运行,在它调用exec或exit之后父进程才可能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。
5、fork要拷贝父进程的进程环境;而vfork则不需要完全拷贝父进程的进程环境,在子进程没有调用exec和exit之前,子进程与父进程共享进程环境,相当于线程的概念,此时父进程阻塞等待。
6、为什么会有vfork呢?
因为以前的fork当它创建一个子进程时,将会创建一个新的地址空间,并且拷贝父进程的资源,然后将会有两种行为:
1.执行从父进程那里拷贝过来的代码段
2.调用一个exec执行一个新的代码段
当进程调用exec函数时,一个新程序替换了当前进程的正文,数据,堆和栈段。这样,前面的拷贝工作就是白费力气了,这种情况下,聪明的人就想出了vfork。vfork并不复制父进程的进程环境,子进程在父进程的地址空间中运行,所以子进程不能进行写操作,并且在儿子“霸占”着老子的房子时候,要委屈老子一下了,让他在外面歇着(阻塞),一旦儿子执行了exec或者exit后,相当于儿子买了自己的房子了,这时候就相当于分家了。
因此,如果创建子进程是为了调用exec执行一个新的程序的时候,就应该使用vfork
https://yq.aliyun.com/articles/48614
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <string.h> #include <sys/syscall.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <sys/types.h> #include <sys/wait.h> /* #include <unistd.h> int execl(const char *pathname, const char *arg, …); int execlp(const char *filename,conxt char *arg, …); int execle(const char *pathname,conxt char *arg, …,char *const envp[ ]); int execv(const char *pathname, char *const argv[ ]); int execvp(const char *filename, char *const argv[ ]); int execve(const char *pathname, char *const argv[ ],char *const envp[ ]); #include <stdlib.h> int system(const char *cmdstring); #include <sched.h> int__clone(int (*fn)(void *arg),void *child_stack,int flags,void *arg); #include <stdlib.h> void exit(int status); int atexit(void (*function)(void)); int on_exit(void(*function)(int, void*), void *arg); void abort(void); #include <unistd,h> void _exit(int status); #include <assert.h> void assert(int expression); */ #ifndef T_DESC #define T_DESC(x, y) (y) #endif #if T_DESC("global", 1) int main(int argc, char **argv) { pid_t pid; int status; if((pid = fork()) < 0) { status = -1; } else if(pid == 0) { printf("child: "); // 执行/bin目录下的ls, 第一参数为程序名ls, 第二个参数为"-al", 第三个参数为"/etc/passwd" execl("/bin/ls", "ls", "-al", "/etc/passwd", (char *) 0); //system("ls -a"); _exit(127); } else { printf("father: 11 "); while(waitpid(pid, &status, 0) < 0) { if(errno != EINTR) { status = -1; break; } } printf("father: 22 "); } return status; } #endif