浅谈fork函数
Posted 霜序0.2℃
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈fork函数相关的知识,希望对你有一定的参考价值。
谈谈进程
从程序员的角度进程有三种状态:
- 进行 正在执行或者等待执行且最终被调度
- 停止 进程被挂起且不会被调度,
- 终止 三种可能:收到终止信号,从主程序返回,调用exit函数
关于进程的函数有exit
,fork
,wait
等,本篇只描述fork
谈谈fork
fork是一个很特殊的函数,用于克隆父进程,创建子进程
一个函数,却有两个返回,挺奇妙的
fork返回的是子进程的PID,即fork之后,子进程是返回的是0(子进程没有子进程了),而父进程返回子进程的PID
0
:在子进程中,pid变量保存的fork( )返回值为0,表示当前进程是子进程
>0
:在父进程中,pid变量保存的fork( )返回值为子进程的id值(进程唯一标识符)
-1
:创建失败
内核为fork( )完成以下操作:
-
为新进程分配一进程表项和进程标识符
进入fork( )后,内核检查系统是否有足够的资源来建立一个新进程。若资源不足,则fork( )系统调用失败;否则,内核为新进程分配一进程表项和唯一的进程标识符。 -
检查同时运行的进程数目
超过预先规定的最大数目时,fork( )系统调用失败。 -
拷贝进程表项中的数据
将父进程的当前目录和所有已打开的数据拷贝到子进程表项中,并置进程的状态为“创建”状态。 -
子进程继承父进程的所有文件
对父进程当前目录和所有已打开的文件表项中的引用计数加1。 -
为子进程创建进程上、下文
进程创建结束,设子进程状态为“内存中就绪”并返回子进程的标识符。 -
子进程执行
虽然父进程与子进程程序完全相同,但每个进程都有自己的程序计数器PC(注意子进程的PC开始位置),然后根据pid变量保存的fork( )返回值的不同,执行了不同的分支语句。
特点
1.调用一次返回两次
父进程返回一次子进程返回一次
2.并发执行
通过计算机调度
3.相同却又独立的地址空间
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
int pid;
int x = 1;
pid = fork();
if (pid == 0) {
printf("chind : x=%d address=%d\\n", ++x, &x);
exit(0);
}
printf("parent : x=%d address=%d\\n", --x, &x);
exit(0);
}
这样的一个函数
我们输出的是
[root@Cai test]# ./test1
parent : x=0 address=-1911367976
[root@Cai test]# chind : x=2 address=-1911367976
由此可见,内存地址完全一样,但是由于是不同的进程,虽然有相同的栈,相同的堆,相同的变量值和地址,但是由于是独立的,对x的改变也是独立的
4.共享文件
例如stdout文件,子进程继承了父进程的打开文件,并指向屏幕,所以父进程和子进程的输出都是指向屏幕
练习1
题目来源:csapp练习8.2
问:父进程和子进程输出什么
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
int x = 1;
if (fork() == 0)
printf("p1: x=%d\\n", ++x);
printf("p2: x=%d\\n", --x);
exit(0);
}
原来的想法:
如果fork等于0,那么并没退出,还需要执行p2的输出,所以:先进行父进程的输出,只输出p2,再进行子进程的输出,p1和p2
p2: x=0
p1: x=2
p2: x=1
事实上:
进程终止的时候,内核并非立即把它删除,而是保持在一种已终止
的状态,直到被他的父进程回收.终止了但还没回收的进程叫僵尸进程
由于父进程终止,子进程还在运行,那么内核会将安排init进程成为它孤儿进程的父进程,init进程是所有进程的祖先(进程),僵尸进程
没有运行,但是仍然消耗内存资源
[root@Cai terminateParent]# ./test
p2: x=0
[root@Cai terminateParent]# p1: x=2
p2: x=1
佐证代码:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
int x = 1;
if (fork() == 0) {
printf("parent pid=%d\\n", getppid());
printf("p1: x=%d\\n", ++x);
}
printf("p2: x=%d\\n", --x);
exit(0);
}
结果:
[root@Cai terminateParent2]# ./test
p2: x=0
[root@Cai terminateParent2]# parent pid=1
p1: x=2
p2: x=1
参考
C语言编译过程
深入理解计算机系统csapp第三版第8章8.4(P513)
以上是关于浅谈fork函数的主要内容,如果未能解决你的问题,请参考以下文章