由fork创建的进程称为子进程(child process),此函数调用一次,返回两次。
子进程返回0值,父进程返回子进程的I 子进程是父进程的副本,它将获得父进程的数据空间,堆栈等资源
注意:有副本,但不共享
推荐下面这篇文章:
fork()详解 文章,请点击.
子进程不会复制父进程的环境,但子进程直接运行在父进程的地址空间,不能进行写操作。
子进程运行时父进程会阻塞,直到子进程执行了exec族或exit,父进程才会执行
1)fork(): 父子进程的执行次序不确定。
vfork():保证子进程先运行,在它调用 exec(进程替换) 或 exit(退出进程)之后父进程才可能被调度运行。
2)fork(): 子进程拷贝父进程的地址空间 ,子进程是父进程的一个复制品。
vfork():子进程共享父进程的地址空间(准确来说,在调用 exec(进程替换) 或 exit(退出进程) 之前与 父进程数据是共享的)
extern char** environ
exec函数族说明
exec 函数族提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新的进程替换了。另外,这里的可执行文件既可以是二进制文件,也可以是 Linux 下任何可执行的脚本文件。
在Linux中使用exec函数族主要有两种情况:
exec函数族语法
所需头文件:#include
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[]);
int execve(const char *path, char *const argv[], char *const envp[]);
函数助记表
位置 | 含义 | 函数 |
---|---|---|
前4位 | 统一为:exec | |
第5位 | l:参数传递为逐个列举方式 | execl、execle、execlp |
v:参数传递为构造指针数组方式 | execv、execve、execvp | |
第6位 | e:可传递新进程环境变量 | execle、execve |
p:可执行文件查找方式为文件名 | execlp、execvp |
事实上,这6个函数中真正的系统调用只有execve(),其他5个都是库函数,它们最终都会调用execve()这个系统调用。在使用exec函数族时,一定要加上错误判断语句。exec 很容易执行失败,其中最常见的原因有:
① 找不到文件或路径,此时 errno 被设置为 ENOENT。
② 数组argv 和envp 忘记用NULL结束,此时,errno被设置为 EFAUL。
③ 没有对应可执行文件的运行权限,此时 errno 被设置为EACCES。
使用execle和execve可以自己向执行进程传递环境变量,但不会继承Shell进程的环境变量,而其他四个exec函数则继承Shell进程的所有环境变量。
int main()
{
char *envp[]={"PATH=/tmp","USER=noodles","STATUS=testing",NULL};
char *argv_execv[]={"echo", "excuted by execv", NULL};
char *argv_execvp[]={"echo", "executed by execvp", NULL};
char *argv_execve[]={"env", NULL};
if(fork()==0){
if(execl("/bin/echo", "echo", "executed by execl", NULL)<0)
perror("Err on execl");
}
if(fork()==0){
if(execlp("echo", "echo", "executed by execlp", NULL)<0)
perror("Err on execlp");
}
if(fork()==0){
if(execle("/usr/bin/env", "env", NULL, envp)<0)
perror("Err on execle");
}
if(fork()==0){
if(execv("/bin/echo", argv_execv)<0)
perror("Err on execv");
}
if(fork()==0){
if(execvp("echo", argv_execvp)<0)
perror("Err on execvp");
}
if(fork()==0){
if(execve("/usr/bin/env", argv_execve, envp)<0)
perror("Err on execve");
}
sleep(1);
return 0;
}
执行结果为:
$ ./fork_C
executed by execl
executed by execlp
PATH=/tmp
USER=noodles
STATUS=testing
excuted by execv
executed by execvp
PATH=/tmp
程序里调用了2个Linux常用的系统命令,echo和env。echo会把后面跟的命令行参数原封不动的打印出来,env用来列出所有环境变量。
由于各个子进程执行的顺序无法控制,所以有可能出现一个比较混乱的输出–各子进程打印的结果交杂在一起,而不是严格按照程序中列出的次序。
用到了exec函数族,一定记得要加错误判断语句。因为与其他系统调用比起来,exec很容易出错,被执行文件的位置,权限等很多因素都能导致该调用的失败。最常见的错误是:
1. 找不到文件或路径,此时errno被设置为ENOENT;
2. 数组argv和envp忘记用NULL结束,此时errno被设置为EFAULT;
3. 没有对要执行文件的运行权限,此时errno被设置为EACCES。