目录
fork 与 vfork:
头文件:
#include<sys/types.h>
#include<unistd.h>
函数原型
fork
pid_t fork(void);
vfork
pid_t vfork(void);
函数功能
fork() 函数和 vfork() 函数一样都是在已有的进程中创建一个新的进程。
fork
返回值:
-1: 函数调用失败,创建子进程失败,且设置errno
0 : 子进程
>0: 在父进程中,且返回值为创建的子进程的进程号
总结:
1.子进程拷贝父进程的数据段,代码段完全复制父进程的资源。这样得到的子进程独立于父进程,具有良好的并发性。
2.fork作用创建子进程,子进程和父进程并行执行,fork创建的子进程和父进程执行的顺序不确定——统一由cpu调度
3.子进程的执行是从fork的下一条语句开始执行,直到子进程退出为止
4.缺点:使用fork创建一个进程时,子进程需要将父进程几乎每种资源都复制,所以fork是一个开销很大的系统调用,这些开销并不是所有情况都需要的。比如fork一个进程后,立即调用exec执行另一个应用程序,那么fork过程中子进程对父进程地址空间的复制将是一个多余的过程。
例:
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
pid_t pid = fork();
if(pid == -1)
{
perror("fork"); //创建失败打印原因
return -1;
}
if(pid == 0) //子进程
{
printf("child process pid: %d,parent process pid: %d\n",getpid(),getppid());
} //getpid返回当前进程标识,getppid返回父进程标识
else //父进程
{
printf("parent pid: %d, parent process pid: %d\n",getpid(),getppid());
}
return 0;
}
运行结果
parent pid: 2834, parent process pid: 2642 先打印父进程 父进程的进程号2834
child process pid: 2835,parent process pid: 2834 在打印子进程 子进程的父进程号2834
有两个打印结果是因为fork在创建子进程后,子进程和父进程并行执行,只不过fork创建的子进程和父进程执行的顺序不确定。(相当于子进程拷贝了父进程 pid_t pid = fork(); 以下的代码段,所以子进程中同样会执行后面的语句,由于子进程中pid == 0为真,所以执行了if语句的内容)。
vfork
返回值
成功:子进程中返回 0,父进程中返回子进程 ID。
失败:返回 -1。
总结
1.使用vfork创建一个子进程时,操作系统并不将父进程的地址空间完全复制到子进程,子进程共享父进程的地址空间,子进程对该地址空间中任何数据的修改同样为父进程所见。
2.使用vfork创建一个子进程时,vfork保证子进程先运行,当他调用exec或exit之后,父进程才可能被调读运行。如果在调用exec或exit之前子进程要依赖父进程的某个行为,就会导致死锁。
3.优点:vfork不会不会像fork一样拷贝父进程的地址空间,这大大减小了系统的开销。
例
#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>
int main(int argc, char *argv[])
{
pid_t pid;
int a = 0;
pid = vfork();
if(pid<0)
{
perror("vfork"); //创建打印失败原因
return -1;
}
else if(pid == 0) //子进程
{
a++;
printf("a = %d\n",a);
printf("Child process,ID is %d\n",getpid());
_exit(0); //结束子进程
}
else //父进程
{
a++;
printf("a = %d\n",a);
printf("Parent process,ID is %d\n",getpid());
}
return 0;
}
运行结果
a = 1
Child process,ID is 3033
a = 2
Parent process,ID is 3032
_exit(0);使得子进程退出,父进程执行,这样else 后的语句就会被父进程执行,又因在子进程调用exec 或exit之前与父进程数据是共享的,所以子进程退出后把父进程的数据段a改成1 了,子进程退出后,父进程又执行,最终就将a变成了2;如果没有_exit(0)的话,子进程没有调用exec 或exit,所以父进程是不可能执行的。