【操作系统实验】进程控制与通信(Linux环境下)

【实验目的】

实验目的:
1、掌握进程的概念,明确进程和程序的区别。
2、认识和了解并发执行的实质。
3、分析进程争用资源的现象,学习解决进程互斥的方法。
实验要求:Linux 环境下完成实验

【实验内容】
(一)进程控制
(二)进程间通信
(1)信号量机制实验
(2)进程的管道通信实验
(3)消息的发送与接收实验
(4)共享存储区通信

【实验环境】(含主要设计设备、器材、软件等)
Pc电脑一台
在这里插入图片描述

【实验步骤、过程】(含原理图、流程图、关键代码,或实验过程中的记录、数据等)

(一)进程控制
1、进程的创建(必做题) 编写一段程序,使用系统调用 fork( )创建两个子进程,在系统中有一个父进程和两个子进程 活动。让每个进程在屏幕上显示一个字符;父进程显示字符“a”,子进程分别显示字符“b” 和“c”。 试观察记录屏幕上的显示结果,并分析原因。
在这里插入图片描述

               图1 os_1_1.c内容
在这里插入图片描述

               图2 os_1_1.c运行结果

原因:在程序执行到fork()之前,只有一个进程正在运行,在程序执行到fork()后,父进程产生子进程,调用fork()之后,父进程的返回值大于0,子进程的返回值等于0,依靠这个来区分父子进程;之后父子进程并行执行并没有先后顺序之分,输出顺序依赖于操作系统内核所用的调度算法,所以使得运行结果不同。

2、 修改已编写的程序,将每个进程的输出由单个字符改为一句话,再观察程序执行时屏幕上出现 的现象,并分析其原因。(必做题)
在这里插入图片描述

               图3 os_1_2.c内容
在这里插入图片描述

               图4 os_1_2.c执行结果-1
在这里插入图片描述

               图5 os_1_2.c执行结果-2

原因:在程序执行到fork()之前,只有一个进程正在运行,在程序执行到fork()后,父进程产生子进程,调用fork()之后,父进程的返回值大于0,子进程的返回值等于0,依靠这个来区分父子进程;之后父子进程并行执行并没有先后顺序之分,输出顺序依赖于操作系统内核所用的调度算法,所以使得运行结果不同。

3、编写程序创建进程树如图 1 和图 2 所示,在每个进程中显示当前进程识别码和父进程识别码。(必 做题)

在这里插入图片描述
在这里插入图片描述

               图6 os_1_3.c内容(进程树1)
在这里插入图片描述

               图7 os_1_3.c运行结果
在这里插入图片描述

               图8 os_1_4.c内容(进程树2)
在这里插入图片描述

               图9 os_1_4.c运行结果

【思考题】
1、系统是怎样创建进程的?
①申请空白PCB
②为新进程分配资源
③初始化进程控制块(初始化标识信息、初始化处理机状态信息、初始化处理机控制信息)
④将新进程插入就绪队列

2、当首次调用新创建进程时,其入口在哪里?
   进程的进程控制块(PCB)结构中的指向其TTS(任务状态段)的指针。
3、当前运行的程序(主进程)的父进程是什么?

   当前运行程序的父进程是该进程的上一个进程

(一)进程间通信
(1)信号量机制实验

1.编写一段程序,使用系统调用 fork( )创建两个子进程,再用系统调用 signal( )让父进程捕捉 键盘上来的中断信号(即按 ctrl+c 键),当捕捉到中断信号后,父进程用系统调用 kill( )向两个 子进程发出信号,子进程捕捉到信号后,分别输出下列信息后终止:
Child process 1 is killed by parent!
Child process 2 is killed by parent!
父进程等待两个子进程终止后,输出以下信息后终止:
Parent process is killed!
在这里插入图片描述

               图10 os_2_11.c内容1
在这里插入图片描述

               图11 os_2_11.c内容2
在这里插入图片描述

               图12 os_2_11.c运行结果
在这里插入图片描述

   图13 signal(SIGINT,stop)放在①号位置程序运行结果
在这里插入图片描述

   图14 signal(SIGINT,stop)放在②号位置程序运行结果

实验要求:
(1)运行程序并分析结果。

   在父进程产生两个进程之前,就对父进程进行signal设置,因为signal函数里面我们用了SIGINT信号,一旦用户输入Ctrl+C,就会执行stop指令,于是结束了waiting()等待的指令从而产生了中断处理,而子进程同样也会相应产生中断,就得到了如图12所示的结果。

(2)如果把 signal(SIGINT,stop)放在①号和②号位置,结果会怎样并分析原因。

   运行结果分别如图13和图14所示,由图可以得到,根据signal的位置不同,所产生的结果也不同,原因在于fork()函数会使得子进程继承父进程的所有信息包括软中断的信息,所以使得signal在不同的位置分别控制着不同的子进程,从而产生了不一样的结果。

(3)该程序段前面部分用了两个 wait(0),为什么?

   等待子进程运行结束。如果子进程没有完成,父进程一直等待。wait( )将调用进程挂起,直至其子进程因暂停或终止而发来软中断信号为止。如果在 wait( )前已有子进程暂停或终止,则调用进程做适当处理后便返回。

(4)该程序段中每个进程退出时都用了语句 exit(0),为什么?
   终止进程的执行。

2、修改上面的程序,增加语句 signal(SIGINT,SIG_IGN)和语句 signal(SIGQUIT,SIG_IGN),再观察程序执行时屏幕上出现的现象,并分析其原因。
在这里插入图片描述

               图15 os_2_12.c内容1
在这里插入图片描述

               图16 os_2_12.c内容2
在这里插入图片描述

               图17 os_2_12.c运行结果

实验要求: 运行程序并分析结果。

   在父进程产生两个进程之前,就对父进程进行signal设置,与第一个例子不同的是这里用了SIGINT和SIGQUIT这两个信号,而且后一句的signal对前一句的设置有覆盖作用,剩下的与第一个例子大体上类似,就得到了如图17所示的结果。

3.司机售票员问题(选做题)

   编程用 fork()创建一个子进程代表售票员,司机在父进程中,再用系统调用 signal()让父进程 (司机)捕捉来自子进程(售票员)发出的中断信号,让子进程(售票员)捕捉来自(司机)发出 的中断信号,以实现进程间的同步运行。

在这里插入图片描述

               图18 os_2_13.c内容

在这里插入图片描述

               图19 os_2_13.c运行结果

(2)进程的管道通信实验

1.编制一段程序,实现进程的管道通信。使用 pipe()建立一条管道线。两个子进程 p1 和 p2 分别 向管道各写一句话:
Child 1 is sending message!
Child 2 is sending message!
而父进程则从管道中读出来自于两个子进程的信息,显示在屏幕上。

在这里插入图片描述

               图20 os_2_21.c内容

在这里插入图片描述

               图21 os_2_21.c运行结果

实验要求: 运行程序并分析结果。

   所谓管道,是指能够连接一个写进程和一个读进程的、并允许它们以生产者—消费者方式进行通信的一个共享文件,又称为pipe文件。由写进程从管道的写入端(句柄 1)将数据写入管道,而读进程则从管道的读出端(句柄 0)读出数据,在本题的程序里面两个子进程往fd[1]中写入内容,而父进程从fd[0]中读取,所以就出现了上述结果。

2.在父进程中用 pipe()建立一条管道线,往管道里写一句话,两个子进程接收这句话。

在这里插入图片描述

               图22 os_2_22.c内容
在这里插入图片描述

               图23 os_2_22.c运行结果

(3)消息的发送与接收实验

1.消息的创建、发送和接收。使用系统调用 msgget( ),msgsnd( ),msgrev( ),及 msgctl( )编制一 长度为1k 的消息发送和接收的程序。
在这里插入图片描述

在这里插入图片描述

               图24 client.c和server.c内容
在这里插入图片描述

               图25 client.c和server.c运行结果

程序说明:

①为了便于操作和观察结果,编制二个程序 client.c 和 server.c,分别用于消息的发送与接收。
②server 建立一个 Key 为 75 的消息队列,等待其它进程发来的消息。当遇到类型为 1 的消息,则 作为 结束信号,取 消该队列 ,并退 出 server。server 每接收 到一个消 息后显示一句 “(server)received。”
③client 使用 key 为 75 的消息队列,先后发送类型从 10 到 1 的消息,然后退出。最后一个消息,即是 server 端需要的结束信号。

2.在父进程中创建一个消息队列,用 fork 创建一个子进程,在子进程中将一条消息传送至消息队 列,父进程接受队列的消息,并将消息送屏幕显示。
在这里插入图片描述

               图26 os_1_31.c内容
在这里插入图片描述

               图27 os_1_31.c运行结果

(4)共享存储区通信
1、编制一长度为 1k 的共享存储区发送和接收的程序。

<程序说明>

①为了便于操作和观察结果,用一个程序作为“引子“,先后 fork()两个子进程,server 和 client, 进行通信。
②server 端建立一个 key 为 75 的共享区,并将第一个字节置为-1,作为数据空的标志。等待其他 进程发来的消息。当该字节的值发生变化时,表示收到了信息,进行处理。然后再次把它的值设为 -1,如果遇到的值为 0,则视为为结束信号,取消该队列,并退出 server。server 每接收到一次数 据后显示“(server)received”。
③client 端建立一个 key 为 75 的共享区,当共享取得第一个字节为-1 时,server 端空闲,可发送 请求。client 随即填入 9 到 0。期间等待 server 端的再次空闲。进行完这些操作后,client 退出。 client 每发送一次数据后显示“(client)sent”。
④父进程在 server 和 client 均退出后结束。
在这里插入图片描述

               图28 os_1_41.c内容1
在这里插入图片描述

               图29 os_1_41.c内容2
在这里插入图片描述

               图30 os_1_41.c运行结果

实验要求: 运行程序并分析结果。
在这里插入图片描述

   共享存储区(Share Memory)是 UNIX 系统中通信速度最高的一种通信机制。该机制可使若干 进程共享主存中的某一个区域,且使该区域出现(映射)在多个进程的虚地址空间中。另一方面,一个进程的虚地址空间中又可连接多个共享存储区,每个共享存储区都有自己的名字。
   对程序的分析结果如下:首先需要先在共享存储区内申请一块区域,用来接收要写的信息,之后建立链接,把共享存储区的内容映射到虚空间内,然后用shmget( )函数 创建并获得一个共享存储区,再用shmat( )函数共享存储区的附接,从逻辑上将一个共享存储区附接到进程的虚拟地址空间上,之后用shmdt( )函数把一个共享存储区从指定进程的虚地址空间断开。

2.编程在主进程中创建两个子进程,在子进程 shmw()中创建一个系统 V 共享内存区,并在其中写入格式化数据;在子进程 shmr()中访问同一个系统 V共享内存区,读出其中的格式化数据。
在这里插入图片描述

               图31 os_1_42.c内容1

在这里插入图片描述

               图32 os_1_42.c内容2
在这里插入图片描述

               图33 os_1_42运行结果
【实验结果或总结】(对实验结果进行相应分析,或总结实验的心得体会,并提出实验的改进意见)

(一)进程控制
   通过之前对于Linux的预备实验,已经大致熟悉了实验环境,并且可以编译运行C文件,从这次实验的结果可以看出,每次程序输出的结果都不尽相同,而这也正是由于多进程并发执行的异步性才会出现的结果。
   经过这次实验,我学会了怎样在Linux环境下创建进程和终止进程,而且懂得如何根据已知的进程树用代码去构建它,并且在多次调试下,理解了什么是多进程之间的异步性,对进程本身对系统资源的占用又有了更深的理解。这次实验把上课讲到的进程的知识也温习了一遍,加深了印象。

(二)进程间通信
(1)信号量机制实验
   此次实验,了解了如何利用信号量机制来完成进程间的通信。本次实验在父进程产生两个进程之前,就对父进程进行signal设置,因为signal函数里面我们用了SIGINT信号,一旦用户输入Ctrl+C,就会执行stop指令,于是结束了waiting()等待的指令从而产生了中断处理,而子进程同样也会相应产生中断。
   在这次实验的过程中,编译和运行代码的时候都出现了很多bug,甚至还有的不知道应该怎么去调试,不过,在个人努力下,还是改完了bug并获得了结果,同时也对信号量机制有了更深层次的理解。
(2)进程的管道通信实验
   此次实验,初步了解了进程间管道通信方式。所谓管道,是指能够连接一个写进程和一个读进程的、并允许它们以生产者—消费者方式进行通信的一个共享文件,又称为pipe文件。由写进程从管道的写入端(句柄 1)将数据写入管道,而读进程则从管道的读出端(句柄 0)读出数据,在本题的程序里面两个子进程往fd[1]中写入内容,而父进程从fd[0]中读取。
   由于自己对管道通信的理解还停留在理论层面,所以在这次实验刚开始时看懂代码费了很长时间,最后理论实践一结合就彻底弄明白了之前在管道通信上遗留下来的一些小问题,同时也分析出来了实验运行结果和原因。
(3)消息的发送与接收实验
   此次实验,主要掌握消息传递的思想和原来,同时也要了解一些在消息的发送与接收中经常用到的函数,就比如其中一些函数会在生产者-消费者问题中实现互斥访问的时候要用到,同时实验指导书上的实验相关资料,以及我在网上阅读的一些博客,让我对这些函数的用法和消息的发送与接收有了进一步的理解和思考。
(4)共享存储区通信
   在这次实验的过程中,我对这种通信方式理解更深了,虽说是共享变量,但是进程间通信要利用到的是临界资源,所以在这里进行通信的时候,都会有lockf()函数,来达到信号量的作用,使两者互斥地通信。
   并且刚好老师让我们用进程实现生产者-消费者问题,在编写代码的过程之中也用到了共享内存,算是对这次实验的理解与应用,也让我更加记住了共享存储区通信这种通信方式它的优点以及便利性。

  • 22
    点赞
  • 133
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小天才才

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值