深入fork

来源:互联网 发布:java中集合的由来 编辑:程序博客网 时间:2024/05/17 10:25
#include <stdio.h>#include <unistd.h>int main(void){  int i = 0;  pid_t pid;  printf("share ostream....");  for (i = 0; i <2; i++)    {    if ((pid = fork()) < 0)      {        printf("forkerror\n");      }    else if (pid == 0)      {        printf("%d,childself's pid=%d,parent's pid=%d,returnid=%d\n", i,            getpid(), getppid(), pid);      }    else      {        printf("%d,parentself's pid=%d,parent's father's pid=%d,returnid=%d\n",            i, getpid(), getppid(), pid);      //in order to child output first     sleep(1);      }  }return 0;}

 

共输出了6次,为什么?



前提:

操作系统中的“进程(process)”概念。一个进程,主要包含三个元素:

o. 一个可以执行的程序;
o. 和该进程相关联的全部数据(包括变量,内存空间,缓冲区等等);
o. 程序的执行上下文(execution context)。

不妨简单理解为,一个进程表示的,就是一个可执行程序的一次执行过程中的一个状态。操作系统对进程的管理,典型的情况,是通过进程表完成的。进程表中的每一个表项,记录的是当前操作系统中一个进程的情况。对于单 CPU的情况而言,每一特定时刻只有一个进程占用 CPU,但是系统中可能同时存在多个活动的(等待执行或继续执行的)进程。

一个称为“程序计数器(program counter, pc)”的寄存器,指出当前占用 CPU的进程要执行的下一条指令的位置。

当分给某个进程的 CPU时间已经用完,操作系统将该进程相关的寄存器的值,保存到该进程在进程表中对应的表项里面;把将要接替这个进程占用 CPU的那个进程的上下文,从进程表中读出,并更新相应的寄存器(这个过程称为“上下文交换(process context switch)”,实际的上下文交换需要涉及到更多的数据,那和fork无关,不再多说,主要要记住程序寄存器pc指出程序当前已经执行到哪里,是进程上下文的重要内容,换出 CPU的进程要保存这个寄存器的值,换入CPU的进程,也要根据进程表中保存的本进程执行上下文信息,更新这个寄存器)。


 

分岔的概念,fork()之后,会从fork()之后分岔出一个子进程B。fork()创建出一个子进程B,同时将父进程A的资源复制给进程B。子进程实质就是对父进程的复制。子进程出了和父进程共享字符text  段意外,其余的都是有自己独立的stack,heap。那么为什么fork()会返回2次呢?我们可以这么理解:在子进程中也有一个fork()在执行,那么他就会返回一个值。对于一个子进程来说,他可以有多个父进程,那么返回不同的数没有任何意思,所以返回0是最合适的,在父进程中,一个父进程可以有多个子进程,那么为了区分进程以及得到子进程号,所以在父进程中需要子进程返回一个子进程号。父进程永远没有办法主动获取子进程号的功能,也没有这种函数,处在在创建进程能返回子进程号之外。

 

     对于复制父进程来创建子进程,这种复制遵循各COW(copy-on-write)即为写时复制。内核并不是完全的复制所有的父进程资源给子进程。创建子进程之后,父进程会将父进程的资源标志为只读,当子进程需要改变资源的时候,就会发生复制,即复制该资源给子进程,让子进程单独自己去处理。

 

为什么输出了6次?

 

 

为什么开始"share ostream...."输出了两次,后面就没有输出了?

 解: 第1次fork进程B复制父进程的资源,当然包括输出流中的资源啦。所以把里面的资源一起输出啦。

注意 流出流中遇到 换行符"\n"时,会 刷新的,输出流 变为空啦。所以呢,第二次fork后,子进程,虽然复制了输出流的资源,但也只是复制了个空。so ....

把printf("share ostream....");换成printf("share ostream....\n");再试一下!

原创粉丝点击