设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客

linux fork函数的精辟解说

2012-2-8 10:47| 发布者: 红黑魂| 查看: 5883| 评论: 0|来自: csdn博客

摘要: 此文原文来源于一个blog,文章的名称为:linux fork函数的精辟解说原文地址:http://blog.chinaunix.net/space.php?uid=12461657do=blogid=3062996感觉这篇文章不错,在此分享下来,在原文的基础上增加了自己的一些 ...
此文原文来源于一个blog,文章的名称为:linux fork函数的精辟解说
原文地址:http://blog.chinaunix.net/space.php?uid=12461657&do=blog&id=3062996
感觉这篇文章不错,在此分享下来,在原文的基础上增加了自己的一些理解和说明。
开始演示:
  1. [root@test code]# cat fork.c  
  2. #include <stdio.h>  
  3. #include <unistd.h>  
  4. #include <sys/types.h>  
  5.   
  6. main()  
  7. {  
  8.     pid_t pid;  
  9.     pid=fork();  
  10.     if (pid < 0)  
  11.         printf("Error in fork!");  
  12.     else if (pid == 0)  
  13.         printf("I am the child process. The process id is %d\n",getpid());  
  14.     else  
  15.         printf("I am the parent process. The process id is %d\n",getpid());  
  16. }  
  17. [root@test code]# gcc fork.c -o fork  
  18. [root@test code]# ./fork  
  19. I am the child process. The process id is 6260  
  20. I am the parent process. The process id is 6259  
先说什么是进程

一个进程,就是一个可执行程序的一次执行过程中的一个状态。

打个比方

    我们把一个大学数学老师比作一个可执行程序,老师就是一个人,相当于一份源码,这个数学老师每个学期可能要教多个班,假设他教1班和2班,时间是一个学期,那么他从开学到期末教这两个班这个过程就是两个进程,两个进程的周期都是一个学期。

    在稍微理解了进程的概念之后,我们说在正在运行的计算机中,不管是Linux或者是Windows系统都运行有很多进程,虽然我们的系统中进程比较多,但是对于单核的CPU而言,每一时刻只能有一个进程占用CPU,其他的进程就可能处在等待执行、就绪、结束等状态(状态名称可能随不同操作系统而相异)。

    那么要使我们的操作系统能够正常执行,操作系统对这些进程的管理,典型的情况,是通过内存中的进程表完成的(这里的进程表不是源码的意思)。进程表中的每一个表项,记录的是当前操作系统中一个进程的情况,比如执行到哪里,下一步要执行什么命令等。

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

好了,有这些概念打底,可以说fork了。当你的程序执行到下面的语句:
pid=fork();
操作系统会进行如下的大概过程:
创建一个新的子进程,而这个子进程是父进程的副本,接下来这两个进行就由操作系统调度,直到程序执行结束。

    那么这个过程,我们可以对其进行更加详细的分析。在执行fork以后,操作系统复制一份当前执行的进程的数据,包括进程的数据空间、堆和栈等,并且在进程表中相应为它建立一个新的表项。上下文也是原进程(父进程)的拷贝。但是父、子进程共享正文段,也就是CPU执行的机器指令部分,这个可共享的,在存储器中只需要一个副本,而且这个副本通常是只读的。


那在什么时候父子进程中就分道扬镳呢?
      从上面的实验结果我们看出那两条打印出来的语句不是在同一个进程里面的,因为在同一个进程里面不可能存在,不通结果的getpid(),事实说明是两个不同进程返回的结果,那么在执行pid=fork()以后,开始出现父、子进程,既然是两个进程,那么接下来谁先被调度,也就是说执行pid=fork()以后,在单核CPU下,只会有一个进程被调度,假设是我们的父进程占用CPU时间,父进程继续执行,操作系统对fork的实现,使这个调用在父进程中返回刚刚创建的子进程的pid(一个正整数),所以下面的if语句中pid<0, pid==0的两个分支都不会执行。所以输出I am the parent process....。

    子进程在之后的某个时候得到调度,它的上下文被换入。我们上面分析过,在子进行创建的时候也会复制父进程的上下文,所以子进程不会从头开始执行,而是从pid=fork()开始执行,基于操作系统对fork的实现,使得子进程中fork调用返回0。所以在这个进程(中pid=0。这个进程继续执行的过程中,if语句中 pid<0不满足,但是pid==0是true。所以输出I am the child process...。

我们下面来看一个和我在上面分析的一个结论似乎存在矛盾的现象
 
  1. [root@test code]# cat fork.c          
  2. #include <stdio.h>  
  3. #include <unistd.h>  
  4. #include <sys/types.h>  
  5.   
  6. main()  
  7. {  
  8.     pid_t pid;  
  9.     printf("fork!");  
  10.     pid=fork();  
  11.     if (pid < 0)  
  12.         printf("Error in fork!\n");  
  13.     else if (pid == 0)  
  14.                 printf("I am the child process. The process id is %d\n",getpid());  
  15.         else  
  16.                 printf("I am the parent process. The process id is %d\n",getpid());  
  17. }  
  18. [root@test code]# gcc fork.c -o fork  
  19. [root@test code]# ./fork              
  20. fork!I am the child process. The process id is 7378  
  21. fork!I am the parent process. The process id is 7377  
  22. [root@test code]#   

    这里我添加了printf("fork!")这一行,执行了以后我们发现,“fork!”打印了两次,我们上面不是说,fork以后的子进程的上下文不是和父进程一样吗,也就是说子进程不会从头开始执行,应该从fork执行,那么fork!的出现不是有矛盾吗?我们再来看看下面的现象


酷毙
1

雷人

鲜花

鸡蛋

漂亮

刚表态过的朋友 (1 人)

  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号