1、实验目的

(1)加深对进程概念的理解,明确进程和程序的区别。
(2)进一步认识并发执行的实质。
(3)分析进程竞争资源现象,学习解决进程互斥的方法。

2、实验预备内容

(1)阅读Linux的sched.h源文件,加深对进程管理概念的理解。
(2)阅读Linux的fork.c源文件,分析进程的创建过程。

3、实验内容

(1)进程的创建
编写一段源程序,使系统调用fork()创建两个子进程,当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示字符“a”;子进程分别显示字符“b”和字符“c”。试观察纪录屏幕上的显示结果,并分析原因。
(2)进程的控制
修改已编写的程序,将每个进程输出一个字符改为每个进程输出一句话,在观察程序执行时屏幕出现的现象,并分析原因。
如果在程序中使用调用lockf()来给每一个子进程加锁,可以实现进程之间的互斥,观察并分析出现的现象。

4、思考

(1)系统是怎样创建进程的?
(2)可执行文件加载时进行了哪些处理?
(3)当首次调用新创建进程时,其入口在哪里?

5、实验过程

5.1进程创建

第一步:

创建fork文件夹,在它下面创建first.c文件

mkdir

操作系统——实验二 进程管理_创建进程


操作系统——实验二 进程管理_子进程_02

第二步:

编写程序:

操作系统——实验二 进程管理_子进程_03

第三步:

编译文件,得到a.out

操作系统——实验二 进程管理_子进程_04

第四步:

运行文件,观察并记录结果

./a.out

操作系统——实验二 进程管理_子进程_05

总结:结果为​​abc​​​或​​bac​​​,因为​​fork()​​​创建进程所需要的时间要多于输出一个字符的时间,所以为​​abc​​​或​​bac​​。

写了一个for循环再次验证结论

操作系统——实验二 进程管理_父进程_06

运行:

操作系统——实验二 进程管理_父进程_07


操作系统——实验二 进程管理_子进程_08


分析:由于函数​​printf()​​输出的字符串之间不会被中断,因此,字符串内部的字符顺序输出时不变。但是,由于进程并发执行时的调度顺序和父子进程的抢占处理机问题,处处字符串的顺序和先后随着执行的不同而发生变化。(摘自操作系统实验指导书)

5.2 进程控制

修改已经编好的程序,将每个进程输出一个字符改为每个进程输出一句话,再观察程序执行时屏幕上出现的现象,并分析原因。

如果在程序中使用系统调用​​lockf()​​来给每一个进程加锁,可以实现进程之间的互斥,观察并分析出现的现象。

将上文建立的​​se.c​​文件中的代码改为以下代码:

操作系统——实验二 进程管理_创建进程_09


结果:

结果1:

操作系统——实验二 进程管理_子进程_10


结果2:

操作系统——实验二 进程管理_父进程_11


分析:当使用​​lockf​​​后​​daughter​​​的​​printf​​​无法被抢占,则先输出​​daughter​​,另外两个的先后取决于进程在处理机中的先后顺序。

思考题

(1)系统是怎样创建进程的?
首先,fork() 函数拷贝当前进程创建子进程。产生的子进程与父进程的区别仅在与 PID 与 PPID 以及某些资源和统计量,例如挂起的信号等。准备好进程运行的地址空间后,exec() 函数族负责读取可执行程序,并将其加载到相应的位置开始执行。(来自百度回答)
(2)可执行文件加载时进行了哪些处理?
将源代码转换为机器可认识代码的过程。编译程序读取源程序(字符流),对之进行词法
和语法的分析,将高级语言指令转换为功能等效的汇编代码,再由汇编程序转换为机器语言,
并且按照操作系统对可执行文件格式的要求链接生成可执行程序。具体经过以下几个处理: C源程序一>编译预处理一>编译一>优化程序一>汇编程序一>链接程序一>可执行文件
(3)当首次调用新创建进程时,其入口在哪里?
在进程队列的ready状态下,由离自己最近的父进程执行调度,即入口在最近的父进程处。(来自百度知道)