目录
1、fork函数简介
使用 fork 函数创建一个进程
pid_t fork(void);
fork 函数调用成功,返回两次
返回值为0,代表当前进程是子进程
返回值是非负数,代表当前进程为父进程
调用失败,返回 -1
2、代码实例研究fork函数之后父子进程的关系
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid;
pid_t pid2;
pid = getpid();
printf("before fork: pid = %d \n",pid);
fork();
pid2 = getpid();
printf("after fork: pid = %d \n",pid2);
if(pid == pid2){
printf("this id father print , pid = %d \n",getpid());
}
else{
printf("this id child print , pid = %d \n",getpid());
}
return 0;
}
结论:
一个函数在没有创建fork函数之前都是父进程在走
一旦到了fork进程之后就会出现两个进程(父进程和子进程)
fork之后具体哪个进程进程在跑不知道,由系统调度决定。但可以确定的是,父子进程都会从fork之后,走代码一遍,所以打印了两次 after fork
直到在选择语句的时候,根据条件,父子进程才根据条件各自跑
3、fork返回值具体情况
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid;
pid_t pid2;
pid_t retpid;
pid = getpid();
printf("before fork: pid = %d \n",pid);
retpid = fork();
pid2 = getpid();
printf("after fork: pid = %d \n",pid2);
if(pid == pid2){
printf("this id father print , retpid = %d ,pid = %d\n",retpid,getpid());
}
else{
printf("this id child print ,retpid = %d , pid = %d \n",retpid,getpid());
}
return 0;
}
结论:
fork的返回值,大于0 的时候,代表是父进程。此时的返回值,刚好是子进程的pid号
而fork的返回值,等于0 的时候,代表的是子进程。此时的子进程的pid号其实是复制了fork大于0 的返回值。
其实意思就是:两次返回的唯一区别是子进程的返回值是0,而父进程的返回值则是新子进程的ID
有点拗口,具体看代码😄吧。
4、vfork函数也可以创建进程,但是与fork不同
关键区别一:
vfork直接使用父进程的存储空间,不拷贝
关键区别二:
vfork保证子进程先运行,当子进程调用exit退出后,父进程才执行
通过代码验证区别,既然vfork是直接使用父进程的储存空间,那么子进程修改的数据,父进程那边也是被修改了。
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt = 0;
pid = vfork();
if(pid > 0){
while(1){
printf("this is father print: pid = %d \n",getpid());
printf("cnt = %d\n",cnt);
sleep(1);
}
}
else if(pid == 0){
while(1){
printf("this is child print: pid = %d \n",getpid());
cnt++;
if(cnt == 3){
exit(0);
//break; 不能使用,原因请看下面4.1点
}
sleep(1);
}
}
return 0;
}
结论:
4.1、如果子进程不是按 exit 这个规则退出,换了其他退出,比如break,则父进程的打印的 cnt 不是 3,是一串数字
4.2、vfork是直接使用父进程的储存空间,那么子进程修改的数据,父进程那边也是被修改了。从代码结果可以看出来,子进程将cnt 改为了3,父进程打印 cnt 就为 3。
而 fork 则是,旧的说法是拷贝了一份空间(新的说法是共享,用的时候就直接调用),父子进程各不影响,各行各事。