目录

一、实验目的

二、实验软硬件要求

三、实验预习

四、实验内容(实验步骤、测试数据等)

1、试运行如下一段代码,观察并截屏纪录屏幕上的显示结果,并分析原因。

1)程序代码

2)实验分析与结果:(对实验结果的分析推荐用进程关系图表示)​编辑

2、编写一段源程序,使系统调用fork()创建两个子进程,当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示字符“a”;子进程分别显示字符“b”和字符“c”。试观察纪录屏幕上的显示结果,并分析原因。

1)程序代码:

2)实验分析与结果:

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

4、如果第三步的实验程序中使用调用lockf(1,1,0)和lockf(1,0,0)来给每一个子进程加锁(锁定屏幕输出)和解锁,可以实现进程之间的互斥,观察并分析出现的现象。

5、关于vfork函数的使用

问题1:打印出的值应该是多少呢?

问题2:如果将上面程序中的fork 改成vfork,运行结果是多少呢?


一、实验目的

  1. 加深对进程概念的理解,明确进程和程序的区别。
  2. 进一步认识并发执行的实质。
  3. 熟悉fork函数的使用。

二、实验软硬件要求

  1、CPU:P4 1.6GHz   内存:1G

  2、Windows7操作平台

3、VMware虚拟机(安装有Ubuntu操作系统

三、实验预习

在Linux下一个进程在内存里有三部分的数据,就是"代码段"、"堆栈段"和"数据段"。"代码段",顾名思义,就是存放了程序代码的数据,假如机器中有数个进程运行相同的一个程序,那么它们就可以使用相同的代码段。"堆栈段"存放的就是子程序的返回地址、子程序的参数以及程序的局部变量。而数据段则存放程序的全局变量,常数以及动态数据分配的数据空间(比如用malloc之类的函数取得的空间)。系统如果同时运行数个相同的程序,它们之间就不能使用同一个堆栈段和数据段。

一个程序一旦调用fork函数,系统就为一个新的进程准备了前述三个段,首先,系统让新的进程与旧的进程使用同一个代码段,因为它们的程序还是相同的,对于数据段和堆栈段,系统则复制一份给新的进程,这样,父进程的所有数据都可以留给子进程,但是,子进程一旦开始运行,虽然它继承了父进程的一切数据,但实际上数据却已经分开,相互之间不再有影响了,也就是说,它们之间不再共享任何数据了。

因此,在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。至于fpid的值为什么在父子进程中不同。“其实就相当于链表,进程形成了链表,父进程的fpid(p 意味point)指向子进程的进程id, 因为子进程没有子进程,所以其fpid为0.

fork()函数一共有三种返回值:

 a)在父进程中,fork返回新创建子进程的进程ID;

 b)在子进程中,fork返回0;

c)如果出现错误,fork返回一个负值;    

创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。

四、实验内容(实验步骤、测试数据等)

1、试运行如下一段代码,观察并截屏纪录屏幕上的显示结果,并分析原因。

1)程序代码

2)实验分析与结果:(对实验结果的分析推荐用进程关系图表示)

1.pid_t定义的类型都是进程号类型。这个语句的意思是定义了一个pid_t类型的变量pid,fork()函数返回一个进程号,这个进程号赋给了pid

2.PID(process ID): PID是程序被操作系统加载到内存成为进程后动态分配的资源。 每次程序执行的时候,操作系统都会重新加载,PID在每次加载的时候都是不同的。

3.PPID(parent process ID):PPID是程序的父进程号。

Fpid若不为0,则显示子进程的PID号

至于PID2607这里PPID号为什么不是2605,大抵是父进程先退出,那子进程就没有父进程了,成了孤儿进程,因此1427进程领养了2386。

至于为什么必须要领养,大抵是没有领养,就变成僵尸进程。

至于为什么是1427领养,大抵是1427进程当时正在运行。linux内核大概是设计成任何一个现成的进程都能领养。

2、编写一段源程序,使系统调用fork()创建两个子进程,当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示字符“a”;子进程分别显示字符“b”和字符“c”。试观察纪录屏幕上的显示结果,并分析原因。

1)程序代码:

2)实验分析与结果:

If(fpid=fork())创建子进程成功

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

 

成功创建一个进程,就循环输出五次一个字符。

4、如果第三步的实验程序中使用调用lockf(1,1,0)和lockf(1,0,0)来给每一个子进程加锁(锁定屏幕输出)和解锁,可以实现进程之间的互斥,观察并分析出现的现象。

注意:关于lockf()在此题中的使用可参考下面的例子。

lockf()函数

利用系统调用lockf(fd,mode,size),对指定区域(有size指示)进行加锁或解锁,以实现进程的同步或互斥。

其中,fd是文件描述字;

mode是锁定方式,mode=1表示加锁,mode=0表示解锁;

size是指定文件fd的指定区域,用0表示从当前位置到文件结尾。

注:有些Linux系统是locking(fd,mode,size)

5、关于vfork函数的使用

问题1:打印出的值应该是多少呢?

当是fork时,数据段中的cnt,父子进程互不影响,所以cnt=1。

问题2:如果将上面程序中的fork 改成vfork,运行结果是多少呢?

vfork保证子进程先运行,在她调用exec或exit之后父进程才可能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。这样上面程序中的fork()改成vfork()后,vfork()创建子进程并没有调用exec或exit,所以最终将导致死锁。

在关于子程序输出的代码进行修改,添加一个_exit(0)使其退出

子进程调用exec 或exit之前与父进程数据是共享的,所以子进程退出后把父进程的数据段count改成1了,子进程退出后,父进程又执行,最终就将count变成了2.

运行结果:

问题3:请对问题1和问题2输出的结果进行比较分析。

fork ():子进程拷贝父进程的数据段,代码段

vfork ():子进程与父进程共享数据段

具体分析写在各问题下。

五、实验体会

操作不够熟练,需要加强练习。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐