文章目录

一、关于printf的缓冲区

1、阻塞3秒后,屏幕上才出现hello​​

Linux 多进程编程fork_数据


2、屏幕上先看到hello,才看到阻塞的现象

Linux 多进程编程fork_数据_02


Linux 多进程编程fork_子进程_03


在这里,​​\n​​​的作用和​​fflush(stdout)​​的作用一样,都是将缓冲区中的数据显示到屏幕上。三种情况下,需要将缓冲区的数据显示到屏幕上,缓冲区刷新、放满、程序结束。由于显示到屏幕上需要使用系统调用功能,所以CPU要从用户态切换为内核态,比较浪费时间,而这个缓冲区则可以提高时间利用效率。

Linux 多进程编程fork_父进程_04

Linux 多进程编程fork_子进程_05


​exit()​​​先​​fflush​​​缓冲区,然后再​​_exit​​​退出程序。而​​_exit​​​直接退出程序,以上的代码执行起来就只能看到阻塞的现象,而没有刷新缓冲区,所以屏幕上不会出现​​hello​

二、关于main函数的参数

Linux 多进程编程fork_数据_06

三、复制进程 fork

pid_t fork(void);

函数返回类型 ​​pid_t​​ 实质是 int 类型,Linux 内核 2.4.0 版本的定义是:

Linux 多进程编程fork_子进程_07


fork 函数会新生成一个进程,调用 fork 函数的进程为父进程,新生成的进程为子进程,子进程会复制父进程的所有资源,做到和父进程一模一样

在父进程中返回子进程的 ​​pid > 0​​​,在子进程中​​返回 0​​​,失败​​返回-1​​​ 。而且子进程也是从被​​fork返回的地方​​开始执行。

Linux 多进程编程fork_父进程_08


父子进程都打印​​变量n​​的地址

Linux 多进程编程fork_数据_09


可以看见父子进程的​​&n​​相同,因为这里打印出来的地址是 逻辑地址而不是物理地址使用getpid()​getppid()​获取进程id

Linux 多进程编程fork_父进程_10


Linux 多进程编程fork_子进程_11

练习一

Linux 多进程编程fork_linux_12


Linux 多进程编程fork_数据_13


解析: 出生时​​i=0​​​的进程打印2次,出生时​​i=1​​的进程打印1次,总共6次

Linux 多进程编程fork_linux_14

练习二

需要考虑缓冲区:

Linux 多进程编程fork_子进程_15


Linux 多进程编程fork_linux_16

中间提示符出现表示最开始执行的那个进程结束了,后面还有数据表示还有子进程没结束

屏幕上总共出现了8次,由于printf是把数据放在了缓冲区,​​fork​​的时候 子进程会复制父进程的所有资源,做到和父进程一模一样。当然也包括了缓冲区,所以会屏幕上会多出2个A。

然而上面带有​​\n​​的代码会使得进程fork的时候,缓冲区都是空的,所以子进程复制的缓冲区并没有数据,最后屏幕上会少两个A。

练习三

Linux 多进程编程fork_linux_17


Linux 多进程编程fork_数据_18


解析: 父进程会产生两个进程,​​子进程1​​​由于​​||​​​左侧返回父进程的pid>0,所以不再执行​​||​​​右侧的​​fork​​​,直接执行​​printf​​​。子进程2由于是父进程执行​​||​​​右侧的​​fork​​​时产生的,所以子进程2直接执行​​printf​​。加上父进程打印结果,一共3个A。关于僵死进程<defunct>

Linux 多进程编程fork_linux_19


退出码存放在​​pcb​​中,子进程的退出码由父进程获取

当父进程在子进程之前结束的时候,子进程会由另一个进程收养,一般而言是1号进程(即init进程)

可以看到这里是被1310进程收养,而1310进程是1号进程fork的

Linux 多进程编程fork_父进程_20

使用​​wait(&exit_code)​​​获取子进程的退出码,如果子进程不结束,父进程将一直阻塞在​​wait​​​。子进程结束后,内存中的进程实体被回收,​​wait​​可以理解为用于处理子进程的pcb的方法

Linux 多进程编程fork_数据_21

Linux 多进程编程fork_linux_22