fork 和 vfork函数详解
先说说区别,两者都是创建一个新的进程:
1.使用fork时,父进程和子进程的执行顺序是随机的(时间片轮转调度决定),而使用vfork时,子进程总是先执行,待子进程结束再执行父进程。
2.使用fork时,父进程将自己的数据复制一份拿给子进程,即子进程是父进程的完全副本,而使用vfork时,子进程共享父进程的数据。
fork函数
作用:创建一个新的进程,实际上是创建一个父进程的完全副本,即将父进程的数据完全拷贝一份给子进程,子进程和父进程的执行顺序是随机的,一般可能看见父进程先于子进程执行是因为创建了子进程后,时间片可能仍然是父进程所有,因此父进程先执行。
函数原型:
pid_t fork();
头文件:
#include <sys/types.h>
#include <unistd.h>
函数功能:
创建一个进程;
返回值:
-1:失败
0:子进程返回0;
>0:父进程返回一个大于0的的整数,该整数是子进程的进程id
fork实例1:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid = fork();
if(pid == -1)
{
perror("fork");
return -1;
}
if(pid == 0)//子进程,pid=0
{
printf("I'm child process,my pid is %d\n", getpid());
}
else//父进程,pid>0
{
printf("I'm parent process,my pid is %d, my child's pid is %d\n", getpid(), pid);
}
return 0;
}
fork实例2:让父进程阻塞,等待子进程运行结束后再运行
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t pid = fork();
if(pid == -1)
{
perror("fork");
return -1;
}
if(pid > 0)
{
//父进程休眠3秒
sleep(3);
printf("I'm parent process,my pid is %d, my child's pid is %d\n", getpid(), pid);
}
else
{
printf("I'm child process,my pid is %d\n", getpid());
}
return 0;
}
终端编译运行:
gcc fork.c -o fork
./fork
vfork函数
作用:vfork函数也是创建一个新的进程,但使用该函数后,子进程先执行,子进程执行结束后再执行父进程,且子进程共享父进程的数据。
函数原型:
pid_t vfork();
头文件:
#include <sys/types.h>
#include <unistd.h>
函数功能:
创建一个进程;
返回值:
-1:失败
0:子进程返回0;
>0:父进程返回一个大于0的的整数,该整数是子进程的进程id
tips:使用该函数,子进程先运行,子进程结束后再运行父进程。
vfork实例1:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid = vfork();
if(pid == -1)
{
perror("vfork");
return -1;
}
if(pid > 0)
{
printf("I'm parent process!my pid is %d,my child's pid is %d\n", getpid(), pid);
}
else
{
printf("I'm child process!my pid is %d\n", getpid());
exit(0);
}
return 0;
}
vfork实例2:让子进程休眠3秒钟
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid = vfork();
if(pid == -1)
{
perror("vfork");
return -1;
}
if(pid > 0)
{
printf("I'm parent process!my pid is %d,my child's pid is %d\n", getpid(), pid);
}
else
{
sleep(3);//子进程休眠3s
printf("I'm child process!my pid is %d\n", getpid());
exit(0);
}
return 0;
}
由实例1和实例2可看出,即使是让子进程休眠3秒,父进程依旧不会先执行,而是等待子进程先执行完毕后再执行父进程。
小tips:
这里我遇见一个小问题,当未在子进程中添加exit()函数时,程序最后运行会报一个段错误!!! 经过查证得知,vfork()创建子进程成功后是严禁使用return的,只能调用exit()或者exec族的函数,否则后果不可预料,在main函数里return和exit()效果一样是有前提的:没有调用vfork。
详细说:
-
return返回函数值,是关键字;exit是一个函数。
-
return是语言级别的,它表示了调用堆栈的返回;而exit是系统调用级别的,它表示了一个进程的结束。
-
return是函数的退出(返回);exit是进程的退出。
-
return是C语言提供的,exit是操作系统提供的(或者函数库中给出的)。
-
return用于结束一个函数的执行,将函数的执行信息传出个其他调用函数使用;exit函数是退出应用程序,删除进程使用的内存空间,并将应用程序的一个状态返回给OS,这个状态标识了应用程序的一些运行信息,这个信息和机器和操作系统有关,一般是 0 为正常退出,非0 为非正常退出。
回);exit是进程的退出。
-
return是C语言提供的,exit是操作系统提供的(或者函数库中给出的)。
-
return用于结束一个函数的执行,将函数的执行信息传出个其他调用函数使用;exit函数是退出应用程序,删除进程使用的内存空间,并将应用程序的一个状态返回给OS,这个状态标识了应用程序的一些运行信息,这个信息和机器和操作系统有关,一般是 0 为正常退出,非0 为非正常退出。
6. 非主函数中调用return和exit效果很明显,但是在main函数中调用return和exit的现象就很模糊,多数情况下现象都是一致的。