写在前面:最近学到Linux的进程间通信,发现以前学的进程有点忘了,就找了一些博客来看,这篇博客讲的挺简单易懂的,就搬运来当笔记了,原文也是转载的找不到出处,有知道的可以告诉我,我再加上。

fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
    1)在父进程中,fork返回新创建子进程的进程ID;
    2)在子进程中,fork返回0;
    3)如果出现错误,fork返回一个负值;

创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。此时,两个进程都从fork开始往下执行,只是pid不同。
    有人可能疑惑为什么不是从#include处开始复制代码的?

看下图:

上图表示一个含有fork的程序,而fork语句可以看成将程序切为A、B两个部分。然后整个程序会如下运行:

step1、设由shell直接执行程序,生成了进程P。P执行完Part. A的所有代码。

step2、当执行到pid = fork();时,P启动一个进程Q,Q是P的子进程,和P是同一个程序的进程。Q继承P的所有变量、环境变量、程序计数器的当前值。

step3、在P进程中,fork()将Q的PID返回给变量pid,并继续执行Part. B的代码。

step4、在进程Q中,将0赋给pid,并继续执行Part. B的代码。

这里有三个点非常关键:

1、P执行了所有程序,而Q只执行了Part. B,即fork()后面的程序。(这是因为Q继承了P的PC-程序计数器)

      2、Q继承了fork()语句执行时当前的环境,而不是程序的初始环境。

      3、P中fork()语句启动子进程Q,并将Q的PID返回,而Q中的fork()语句不启动新进程,仅将0返回。

#include <unistd.h> 
#include <sys/types.h>

main () 

         pid_t pid; 
         printf("hello!\n");  
         pid=fork();

if (pid < 0) 
                 printf("error in fork!"); 
         else if (pid == 0) 
                 printf("i am the child process, my process id is %d\n ",getpid());
         else 
                 printf("i am the parent process, my process id is %d\n",getpid());

printf("bye!\n");

这里可以看出parent process执行了printf("hello!\n");  而child process 没有执行printf("hello!\n");

有一个让人很迷惑的例子:

#include <unistd.h>
#include <sys/types.h>

main () 

         pid_t pid; 
         printf("fork!");    //printf("fork!\n")

pid=fork();

if (pid < 0) 
                 printf("error in fork!\n"); 
         else if (pid == 0) 
                 printf("i am the child process, my process id is %d\n",getpid());
         else 
                 printf("i am the parent process, my process id is %d\n",getpid());
}

此时打印输出了两个fork!这不免让人以为是child process从#include处开始执行,所以也执行了printf("fork!"); 语句。

其实不然,出现这种问题的原因在于:

这就跟Printf的缓冲机制有关了,printf某些内容时,操作系统仅仅是把该内容放到了stdout的缓冲队列里了,并没有实际的写到屏幕上 。但是,只要看到有\n, 则会立即刷新stdout,因此就马上能够打印了.

mian函数(parent process)运行了printf("fork!") 后, "fork!"仅仅被放到了缓冲里,再运行到fork时,缓冲里面的 AAAAAA 被子进程(child process)继承了,因此在子进程度stdout缓冲里面就也有了"fork!"。所以,你最终看到的会是 "fork!" 被printf了2次!!!! 
而mian函数(parent process)运行 printf("fork!\n")后,"fork!" 被立即打印到了屏幕上,之后fork到的子进程(child process)里的stdout缓冲里不会有"fork!"内容 因此你看到的结果会是"fork!" 被printf了1次!!!!

                                </div><link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-e9f16cbbc2.css" rel="stylesheet"></div>

fork()与pid相关推荐

  1. linux父进程中显示子进程pid,请教linux下c语言函数fork父进程打印子进程的PID

    请教linux下c语言函数fork父进程打印子进程的PID 关注:296  答案:2  信息版本:手机版 解决时间 2019-01-14 04:55 雨不眠的下 2019-01-13 12:23 用于 ...

  2. 进程控制 父进程子进程 fork pid

    进程:正在运行的程序(分配资源:内存,CPU,IO等) 程序:有限指令的集合(静态:没有执行,存放在外存) 并发:多个任务"同时"执行. (处理器某一时刻最多只运行一个进程) 1. ...

  3. 一个fork短码的扩展版本

    原本代码: 链接 int skip = !!fork() + 2*(!!fork()); for (uint32_t i=skip;i!=INT_MAX;i+=4) { } 这个是多进程加速循环的代码 ...

  4. 【Linux】多线程中使用fork()

    (最核心的东西我在下面用红色字体标出来了,理解了那块,这些东西都是就理解了!) 在本篇文章开始之前,需要大家先了解线程和进程,这位大哥讲的言简意赅:进程和线程的主要区别(总结)_kuangsongha ...

  5. 进程创建函数fork()和vfork()

    Linux下使用fork()创建一个新的进程,该函数不需要参数,返回值是一个进程id.对于不同的对象,分别是:新建的子进程id(返回给父进程),0(返回给创建的子进程)或者-1(子进程创建失败,返回给 ...

  6. c语言exit和return区别,在fork和vfork中使用

    转自c语言exit和return区别,在fork和vfork中使用 exit函数在头文件stdlib.h中. 简述: exit(0):正常运行程序并退出程序: exit(1):非正常运行导致退出程序: ...

  7. linux 内核 fork,《Linux内核分析》之分析fork函数对应的系统调用处理过程

    实验过程 [toggle hide="yes" title="实验过程" color="#f50000"] 1.在实验楼中shell终端依次 ...

  8. 【转】vfork 和 fork的区别

    fork()与vfock()都是创建一个进程,那他们有什么区别呢?总结有以下三点区别: 1.  fork  ():子进程拷贝父进程的数据段,代码段     vfork ( ):子进程与父进程共享数据段 ...

  9. linux fork函数浅析

    #include <sys/types.h> #include <unistd.h> /* 功能:复制进程 參数:无 返回值: 成功: 父进程:返回子进程id 子进程:返回0 ...

最新文章

  1. Oracle中concat与||区别(以及与mysql中concat函数区别)
  2. WAMP 2.2 配置与IIS共用单IP,多域名多网站配置方法
  3. canvas 实现图片局部模糊_Canvas模糊化处理图片、毛玻璃处理图片之stackblur.js
  4. uni-app微信小程序动态样式设置;微信小程序style行内式无效;微信小程序style行内式编译报错;微信小程序:style设置样式
  5. Spring集成Mybatis多数据源配置
  6. C#基础概念之延迟加载
  7. (转)python3 urllib.request.urlopen() 错误UnicodeEncodeError: 'ascii' codec can't encode characters...
  8. 计算机注册表管理,如何打开计算机注册表编辑器
  9. Element UI 进度条文字样式修改
  10. css 头像外圈白_如何使用css实现一个圆形头像框
  11. Android Studio 插件-Android Styler 的使用
  12. 视频算法经理岗位描述(工业方向)
  13. mysql 28000 远程_启用远程MySQL连接:错误1045(28000):拒绝用户访问
  14. 汇编——从一道题目浅谈分支结构
  15. python 抓取网页数据
  16. 设置控件的视觉效果(Win32)
  17. 什么是黄金ETF持仓?
  18. bootstrap table合并单元格mergeCell
  19. log4cplus:ERROR No appenders could be found for logger (AdSyncNamespace).
  20. 苹果id密码忘了怎么办?轻松重置,赶紧收藏!

热门文章

  1. 效率系列(四) VS常用快捷键
  2. swift UI专项训练39 用Swift实现摇一摇功能
  3. js面向对象的封装方法,【案例】
  4. Perl Nmap报告处理摸索(学习)
  5. 将Excel数据导入SQL Server数据库
  6. Hive常用的SQL命令操作
  7. 我的世界java版gamemode指令_我的世界切换生存和创造模式的命令是什么?
  8. 腾讯offer是什么样子_记一次腾讯社招前端面试(已拿到offer入职)
  9. 【错误记录】编译 Android 版本的 ijkplayer 报错 ( ./init-android.sh: 第 37 行: cd: android/contrib/: 没有那个文件或目录 )
  10. 【错误记录】Google Play 上架报错 ( 您的应用包含违反“元数据”政策的内容 | GP 政策中心 )