fork()函数的理解:
含义: os.fork()函数会从调用此函数的地方创建出子进程,子进程会与主进程(即父进程)一起在CPU内执行。
注意:os.fork()函数只在linux环境下才有用,如果是windows环境下,会报错 no os.fork()。
1、每个进程都有一个独特(互不相同)的进程标识符(process ID),可以通过getpid()函数获得,还有一个记录父进程pid的变量,可以通过getppid()函数获得变量的值。
fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值: 返回值为0,代表当前进程是子进程; 返回值为非负数(>0),代表当前进程是父进程 调用失败,返回-1 直接返回getpid()的值,则表示当前进程PID
2、使用fork函数创建一个进程,实验举例
#include#include #include #include int main() { pid_t pid; pid=fork(); //创建子进程 if(pid<0) printf("error in fork"); else if(pid==0) printf("I am the child process,ID is %dn", getpid()); else printf("I am the parent process,ID is %dn", getpid()); }
运行结果:
I am the child process,ID is 2723 I am the parent process,ID is 2722
实验程序分析:
1)pid=fork();
先来看看子进程的表现:
操作系统调用fork()函数创建一个新的进程(子进程),并且在进程表中相应为它建立一个新的表项,
此时子进程得到CPU的调度,它的上下文被换入,占据 CPU,操作系统对fork的实现,使得子进程中fork调用返回0
所以在这个进程中pid=0,这个进程继续执行的过程中,if语句中 pid<0不满足,但是pid= =0是true。所以输出i am the child process…
父进程的表现:
操作系统对fork的实现,使这个调用在父进程中返回刚刚创建的子进程的pid(一个正整数),所以下面的if语句中pid<0,pid==0的两个分支都不会执行。所以输出i am the parent process…
2)对子进程来说,fork返回给它0,但它的pid绝对不会是0,之所以fork返回0给它,是因为它随时可以调用getpid()来获取自己的pid
3)fork之后父子进程除非采用了同步手段,否则不能确定谁先运行,也不能确定谁先结束.认为子进程结束后父进程才从fork返回的,这是不对的,fork不是这样的,vfork才这样。
4)父进程执行了所有的进程,而子进程只执行了fork()后面的程序,这是因为子进程继承了父进程的PC(程序计数器).
vfork与fork的区别
vfork与fork主要有三点区别: .fork():子进程拷贝父进程的数据段,堆栈段 vfork():子进程与父进程共享数据段 .fork()父子进程的执行次序不确定vfork 保证子进程先运行,在调用 exec 或 exit 之前与父进程数据是共享的,在它调用 exec或 exit 之后父进程才可能被调度运行。 .vfork()保证子进程先运行,在它调用 exec 或 exit 之后父进程才可能被调度运行.如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。
(1)先用fork()进行试验
#include#include int main(void) { pid_t pid; int count=0; pid=fork(); count++; printf("count= %dn",count); return 0; }
分析:
通过上面fork()的说明,这个程序的输出应该是:
./test
count= 1
count= 1
(2)而将fork()换成vfork()呢,程序如下
#include#include int main(void) { pid_t pid; int count=0; pid=vfork(); count++; printf("count= %dn",count); return 0; }
./test 执行结果:
count= 1
count= 1
Segmentation fault (core dumped)
分析:
通过将fork()换成vfork(),由于vfork()是共享数据段,为什么结果不是2呢?
答案是: vfork保证子进程先运行,在它调用 exec 或 exit 之后父进程才可能被调度运行.如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁.
(3)做最后的修改,在子进程执行时,调用_exit(),程序如下:
#include#include #include int main(void) { pid_t pid; int count=0; pid=vfork(); if(pid==0) { count++; _exit(0); } else { count++; } printf("count= %dn",count); return 0; }
./test 执行结果:
count= 2
分析:如果子进程中如果没有调用_exit(0),则父进程不可能被执行,在子进程调用exec(),exit()之后父进程才可能被调用.
所以加上_exit(0),使子进程退出,父进程执行.
这样 else 后的语句就会被父进程执行,又因在子进程调用 exec 或 exit 之前与父进程数据是共享的,
所以子进程退出后把父进程的数据段 count 改成1了,子进程退出后,父进程又执行,最终就将count 变成了 2.



