1、fork函数简介
参考:https://www.jianshu.com/p/484af1700176
-
一个进程,包括代码、数据和分配给进程的资源。fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
-
一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。
#include <stdio.h>
#include <unistd.h> // (windows没有unistd.h)
int main()
{
pid_t fpid;
int count = 0;
fpid = fork();
if(fpid < 0) {
printf("error in fork\n");
} else if(fpid == 0) {
// 表示子进程
printf("son process\n");
++count;
} else {
// > 0表示父进程
printf("father process\n");
++count;
}
printf("fpid = %d , count = %d\n", fpid, count);
return 0;
}
(macos + xcode)运行结果是:
father process
fpid = 13915 , count = 1
son process
fpid = 0 , count = 1
其实就相当于链表,进程形成了链表,父进程的fpid(p 意味point)指向子进程的进程id, 因为子进程没有子进程,所以其fpid为0.
fork出错可能有两种原因:
-
当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。
-
系统内存不足,这时errno的值被设置为ENOMEM。
fork()产生的子进程不是从#include处开始复制代码的,这是因为fork是把进程当前的情况拷贝一份,执行fork时,进程已经执行完了int count=0;fork只拷贝下一个要执行的代码到新的进程。
2、fork进阶知识
#include <unistd.h>
#include <stdio.h>
int main(void)
{
int i=0;
printf("i son/pa ppid pid fpid/n");
//ppid指当前进程的父进程pid
//pid指当前进程的pid,
//fpid指fork返回给当前进程的值
for(i=0;i<2;i++){
pid_t fpid=fork();
if(fpid==0)
printf("%d child %4d %4d %4d/n",i,getppid(),getpid(),fpid);
else
printf("%d parent %4d %4d %4d/n",i,getppid(),getpid(),fpid);
}
return 0;
}
运行结果:
i son/pa ppid pid fpid
0 parent 2043 3224 3225
0 child 3224 3225 0
1 parent 2043 3224 3226
1 parent 3224 3225 3227
1 child 1 3227 0
1 child 1 3226 0
这份代码比较有意思,我们来认真分析一下:
-
由于第二行的输出可以看出来,当前进程的pid是3224,其父进程的pid是2043,在i=0的时候执行fork产生子进程pid=3225,2043-->3224-->3225;
-
第三行的输出是由pid=3224通过fork产生的子进程pid=3225,每一个子进程的fpid都是0
-
第四行输出是由于迭代到i=1的时候,当前进程pid=3224的进程第二次执行fork函数产生新的子进程pid=3226, 2043-->3224-->3226; 当输出后pid=3224的进程结束了
-
第五行输出是由于第一次执行fork函数的时候产生的子进程得到的i=0,还需要执行下一次i=1的操作,因此pid=3225也会产生属于它的子进程,pid=3227,此时pid=3225的子进程相对于pid=3227的进程来说,它自己就是父进程,3224-->3225-->3227; 当输出后pid=3225的进程结束了
-
第六行的输出是来自于pid=3227的子进程,fpid=0;为啥ppid=1呢?而不是3225,因为3225的进程已经结束了,pid = 1是永远不会死亡的
-
第七行的输出来自于pid=3226,(由于第二次执行fork产生的子进程),同上ppid=1(3224的进程已经结束了)
网友评论