文章目录
一、关于printf的缓冲区
1、阻塞3秒后,屏幕上才出现hello
2、屏幕上先看到hello
,才看到阻塞的现象
在这里,\n
的作用和fflush(stdout)
的作用一样,都是将缓冲区中的数据显示到屏幕上。三种情况下,需要将缓冲区的数据显示到屏幕上,缓冲区刷新、放满、程序结束。由于显示到屏幕上需要使用系统调用功能,所以CPU要从用户态切换为内核态,比较浪费时间,而这个缓冲区则可以提高时间利用效率。
exit()
先fflush
缓冲区,然后再_exit
退出程序。而_exit
直接退出程序,以上的代码执行起来就只能看到阻塞的现象,而没有刷新缓冲区,所以屏幕上不会出现hello
二、关于main函数的参数
三、复制进程 fork
pid_t fork(void);
函数返回类型 pid_t
实质是 int 类型,Linux 内核 2.4.0 版本的定义是:
fork 函数会新生成一个进程,调用 fork 函数的进程为父进程,新生成的进程为子进程,子进程会复制父进程的所有资源,做到和父进程一模一样。
在父进程中返回子进程的 pid > 0
,在子进程中返回 0
,失败返回-1
。而且子进程也是从被fork返回的地方
开始执行。
父子进程都打印变量n
的地址
可以看见父子进程的&n
相同,因为这里打印出来的地址是 逻辑地址而不是物理地址使用getpid()
和getppid()
获取进程id
练习一
解析: 出生时i=0
的进程打印2次,出生时i=1
的进程打印1次,总共6次
练习二
需要考虑缓冲区:
中间提示符出现表示最开始执行的那个进程结束了,后面还有数据表示还有子进程没结束
屏幕上总共出现了8次,由于printf是把数据放在了缓冲区,fork
的时候 子进程会复制父进程的所有资源,做到和父进程一模一样。当然也包括了缓冲区,所以会屏幕上会多出2个A。
然而上面带有\n
的代码会使得进程fork的时候,缓冲区都是空的,所以子进程复制的缓冲区并没有数据,最后屏幕上会少两个A。
练习三
解析: 父进程会产生两个进程,子进程1
由于||
左侧返回父进程的pid>0,所以不再执行||
右侧的fork
,直接执行printf
。子进程2由于是父进程执行||
右侧的fork
时产生的,所以子进程2直接执行printf
。加上父进程打印结果,一共3个A。关于僵死进程<defunct>
退出码存放在pcb
中,子进程的退出码由父进程获取
当父进程在子进程之前结束的时候,子进程会由另一个进程收养,一般而言是1号进程(即init进程)
可以看到这里是被1310进程收养,而1310进程是1号进程fork的
使用wait(&exit_code)
获取子进程的退出码,如果子进程不结束,父进程将一直阻塞在wait
。子进程结束后,内存中的进程实体被回收,wait
可以理解为用于处理子进程的pcb的方法