`
fp_moon
  • 浏览: 983110 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

linux fork函数的精辟解说

阅读更多

文章的名称为:linux fork函数的精辟解说

原文地址:http://blog.chinaunix.net/space.php?uid=12461657&do=blog&id=3062996

 

  开始演示:[plain]view plaincopyprint?

  [root@test code]# cat fork.c #include <stdio.h> #include <unistd.h> #include <sys/types.h>

  main()

  { pid_t pid;pid=fork();if (pid < 0)

  printf("Error in fork!");else if (pid == 0)

  printf("I am the child process. The process id is %d\n",getpid());else printf("I am the parent process. The process id is %d\n",getpid());} [root@test code]# gcc fork.c -o fork [root@test code]# ./fork I am the child process. The process id is 6260 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……。

  我们下面来看一个和我在上面分析的一个结论似乎存在矛盾的现象

  [plain]view plaincopyprint?

  [root@test code]# cat fork.c #include <stdio.h> #include <unistd.h> #include <sys/types.h>

  main()

  { pid_t pid;printf("fork!");pid=fork();if (pid < 0)

  printf("Error in fork!\n");else if (pid == 0)

  printf("I am the child process. The process id is %d\n",getpid());else printf("I am the parent process. The process id is %d\n",getpid());} [root@test code]# gcc fork.c -o fork [root@test code]# ./fork fork!I am the child process. The process id is 7378 fork!I am the parent process. The process id is 7377 [root@test code]#

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

  [plain]view plaincopyprint?

  <span style="font-family:Courier New;">[root@test code]# cat fork.c #include <stdio.h> #include <unistd.h> #include <sys/types.h>

  main()

  { pid_t pid;printf("fork!\n");pid=fork();if (pid < 0)

  printf("Error in fork!\n");else if (pid == 0)

  printf("I am the child process. The process id is %d\n",getpid());else printf("I am the parent process. The process id is %d\n",getpid());} [root@test code]# gcc fork.c -o fork [root@test code]# ./fork fork!

  I am the child process. The process id is 7458 I am the parent process. The process id is 7457 [root@test code]#</span>

  这里我在printf("fork!")这一行的fork!后面添加了一个换行符,变成printf("fork!\n")执行以后发现只打印一个fork!这个到底是什么原因呢?

  主要的区别是因为有了一个\n 回车符号,说起真正的原因,这和printf的缓冲机制有关了,printf某些内容时,操作系统仅仅是把该内容放到了stdout的缓冲队列里了,并没有实际的写到屏幕上,但是只要看到有\n 则会立即刷新stdout,因此就马上能够打印了。

  还没有执行到fork()的时候,原进程运行了printf("fork!") 后,fork!仅仅被放到了缓冲里,执行了fork,这时候子进程复制一份父进程的数据,包括这个stdout缓冲,在子进程度stdout缓冲里面就也有了fork!。执行到后面这两个缓冲都打印到屏幕上,所以出现两次,并不是printf执行两次。而运行 printf("fork!\n")后, fork!被立即打印到了屏幕上,之后fork到的子进程里的stdout缓冲里不会有fork!内容,因此你看到的结果会是fork!被printf了1次!!!

 printf("hello!"); 
//fflush(stdout);  
 fork(); 
输出:hello!hello!

 

printf("hello!"); 
fflush(stdout);  

fork(); 
输出:hello!

 

原文链接: http://linux.chinaitlab.com/kern...

分享到:
评论

相关推荐

    linux_fork函数

    ### Linux中的`fork()`函数详解 #### 一、`fork()`函数基础介绍 在Linux操作系统中,`fork()`函数是一个非常重要的系统调用,用于创建一个新的进程。这个新进程被称为子进程,而调用`fork()`函数的原进程则称为父...

    linux内核 do_fork 函数源代码浅析

    ### Linux 内核 do_fork 函数源代码浅析 #### 一、引言 在 Linux 内核中,进程的创建是一项基本且重要的功能。本文将深入剖析 do_fork 函数,它作为核心组件之一,在 Linux 内核中扮演着创建新进程的关键角色。do_...

    创建新进程:fork函数:fork函数干什么? fork函数与vfork函数的区别在哪里?为何在一个fork的子进程分支中使用_exit函数而不使用exit函数?

    创建新进程:fork 函数 fork 函数是 UNIX 统操作系统中用于创建新进程的系统调用。它创建了一个完全相同的子进程副本,并返回一个进程标识符(PID)。fork 函数的返回值在父进程和子进程中不同:在父进程中,返回子...

    linux fork函数

    在Linux操作系统中,`fork()`函数是创建新进程的关键接口,它是C标准库中的一个系统调用。这个函数允许一个正在运行的进程(父进程)创建一个与它几乎完全相同的副本,即子进程。理解并熟练使用`fork()`是进行进程...

    fork 函数详解

    fork 函数详解 fork 函数是 Unix 系统中一个非常重要的系统调用,它允许一个进程创建一个新的进程,该新的进程是原来进程的副本。fork 函数的返回值在父进程和子进程中不同,在父进程中返回新创建的子进程的进程 ID...

    linux下fork函数实例

    用fork创建子进程; 回答no执行父进程,yes执行父进程并复制进程的操作;在父进程将str3,str4接至str0中,并输出str0 ;在子进程中,将str1,str2接至str0中,并输出str0

    fork函数和子函数进程

    其中,`fork()`函数是Unix/Linux系统中创建新进程的核心手段。通过深入理解`fork()`函数的工作原理及其在进程管理中的应用,可以有效地提升程序员在多进程程序设计方面的能力。本文将从`fork()`函数的基本概念出发,...

    c语言的fork函数笔记

    ### c语言中的`fork()`函数详解 #### 一、引言 `fork()`函数作为操作系统提供的核心系统调用之一,在进程管理和并发编程中扮演着重要角色。本文将深入探讨`fork()`函数的基本概念、工作原理及其在C语言中的具体应用...

    演示fork函数的效果

    在Linux或Unix操作系统中,`fork()`函数是一个非常核心且重要的系统调用,它用于创建一个新进程。这个过程被称为进程复制或者 fork。通过`fork()`,父进程能够创建一个与自身几乎完全相同的子进程,两个进程各自拥有...

    在win系统下模拟linux中的fork()函数执行过程与基础通信过程

    在win系统下模拟linux中的fork()函数执行过程与基础通信过程 备注清晰。

    linuxC函数手册.chm

    5. **进程与线程**:Linux提供了一套丰富的系统调用来管理进程和线程,如fork()创建新进程,exec()系列函数执行新的程序,pthread_create()创建线程,pthread_join()等待线程结束等。 6. **信号处理**:通过...

    Linux C 函数详解

    此外,针对Linux系统,书中还详细讲解了与系统交互的函数,如fork用于创建子进程,exec系列函数用于执行新的程序,以及socket函数用于网络通信等。这些都是Linux开发中不可或缺的部分,对于理解和编写系统级程序至关...

    linux c语言函数速查手册

    在Linux下,可以使用`pthread`库创建和管理线程,`fork`创建子进程,`wait`和`waitpid`等待子进程结束。 八、网络编程 `socket`函数创建套接字,`bind`绑定IP地址和端口,`listen`等待连接,`accept`接收连接,`...

    fork函数使用

    关于fork函数的介绍,和测试程序,原版fork linux平台

    linux中fork()函数详解.docx

    Linux 中 fork() 函数详解 fork() 函数是 Linux 操作系统中最基本也是最重要的系统调用之一,它允许一个进程创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的...

    linux c fork全面剖析

    ### Linux C 中 fork() 函数全面剖析 #### 进程概念及上下文 要深入了解 `fork()` 函数的工作原理,首先要理解操作系统中的“进程”这一基本概念。在计算机科学中,“进程”通常指的是一个可执行程序的一次执行...

    linux 进程 线程 fork 的深入思考

    本篇文章将基于一道经典的面试题目来探讨 Linux 下进程创建机制,特别是 `fork` 函数的工作原理。该题目不仅考验应试者对进程创建的理解,还涉及了对进程间关系的认识。 #### 题目描述 假设有一段 C 语言程序,在 ...

    linux系统函数(chm)

    Linux系统函数是Linux操作系统中用于实现特定功能的预编译函数库,它们是C语言编程接口的一部分,允许程序员与操作系统内核进行交互。这个压缩包文件"Linux系统函数.chm"很可能是一个帮助文档,详细介绍了各种Linux...

    linux下socket和fork结合使用的例子

    在Linux操作系统中,`socket`、`fork`和`c/c++`是构建网络应用程序的常见工具。`socket`用于创建通信端点,允许不同进程间进行数据交换,`fork`则是Unix/Linux系统中用于创建新进程的关键系统调用。本示例中,我们将...

Global site tag (gtag.js) - Google Analytics