操作系统--进程管理与进程通信

实验目的

1、掌握进程的概念,明确进程的含义。
2、认识并了解进程并发执行的实质,进程的阻塞与唤醒,终止与退出的过程。
3、熟悉进程的睡眠、同步、撤消等进程控制方法。
4、分析进程竞争资源的现象,学习解决进程互斥的方法 。
5、了解什么是信号,利用信号量机制熟悉进程间软中断通信的基本原理,
6、熟悉消息传送的机理 ,共享存储机制 。

实验内容

1、编写一段程序,使用系统调用fork( )创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程并发执行,观察实验结果并分析原因。
2、用fork( )创建一个进程,再调用exec( ),用新的程序替换该子进程的内容,利用wait( )来控制进程执行顺序,掌握进程的睡眠、同步、撤消等进程控制方法,并根据实验结果分析原因。
3、编写一段多进程并发运行的程序,用lockf( )来给每一个进程加锁,以实现进程之间的互斥,观察并分析出现的现象及原因。
4、编写程序:用fork( )创建两个子进程,再用系统调用signal( )让父进程捕捉键盘上来的中断信号(即按^c键);捕捉到中断信号后,父进程用系统调用kill( )向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止:
Child process1 is killed by parent!
Child process2 is killed by parent!
父进程等待两个子进程终止后,输出如下的信息后终止:
Parent process is killed!
分析利用信号量机制中的软中断通信实现进程同步的机理。
5、使用系统调用msgget( ),msgsnd( ),msgrev( ),及msgctl( )编制一长度为1k的消息发送和接收的程序,并分析消息的创建、发送和接收机制及控制原理。
6、编制一长度为1k的共享存储区发送和接收的程序,并设计对该共享存储区进行互斥访问及进程同步的措施,必须保证实现正确的通信。

实验原理

1、进程创建与进程并发执行
Linux中,进程既是一个独立拥有资源的基本单位,又是一个独立调度的基本单位。一个进程实体由若干个区(段)组成,包括程序区、数据区、栈区、共享存储区等。每个区又分为若干页,每个进程配置有唯一的进程控制块PCB,用于控制和管理进程。
系统为每个进程配置了一张进程区表。表中,每一项记录一个区的起始虚地址及指向系统区表中对应的区表项。核心通过查找进程区表和系统区表,便可将区的逻辑地址变换为物理地址。
进程是进程映像的执行过程,也就是正在执行的进程实体。它由三部分组成:
(1)用户级上、下文。主要成分是用户程序;
(2)寄存器上、下文。由CPU中的一些寄存器的内容组成,如PC,PSW,SP及通用寄存器等;
(3)系统级上、下文。包括OS为管理进程所用的信息,有静态和动态之分。
2、进程的睡眠、同步、撤消等进程控制
用fork( )创建一个进程,再调用exec( )用新的程序替换该子进程的内容,然后利用wait( )来控制进程执行顺序。
3、多进程通过加锁互斥并发运行
用lockf( )来给每一个进程加锁,以实现多进程之间的互斥。
所涉及的系统调用:lockf(files,function,size),用作锁定文件的某些段或者整个文件。
4、进程间通过信号机制实现软中断通信
(1)信号的基本概念
每个信号都对应一个正整数常量(称为signal number,即信号编号。定义在系统头文件<signal.h>中),代表同一用户的诸进程之间传送事先约定的信息的类型,用于通知某进程发生了某异常事件。每个进程在运行时,都要通过信号机制来检查是否有信号到达。若有,便中断正在执行的程序,转向与该信号相对应的处理程序,以完成对该事件的处理;处理结束后再返回到原来的断点继续执行。实质上,信号机制是对中断机制的一种模拟,故在早期的UNIX版本中又把它称为软中断。
(2)信号的发送
信号的发送,是指由发送进程把信号送到指定进程的信号域的某一位上。如果目标进程正在一个可被中断的优先级上睡眠,核心便将它唤醒,发送进程就此结束。一个进程可能在其信号域中有多个位被置位,代表有多种类型的信号到达,但对于一类信号,进程却只能记住其中的某一个。
进程用kill( )向一个进程或一组进程发送一个信号。
(3)对信号的处理
当一个进程要进入或退出一个低优先级睡眠状态时,或一个进程即将从核心态返回用户态时,核心都要检查该进程是否已收到软中断。当进程处于核心态时,即使收到软中断也不予理睬;只有当它返回到用户态后,才处理软中断信号。
5、消息的发送与接收
使用系统调用msgget( ),msgsnd( ),msgrev( ),及msgctl( )编制一长度为1k的消息发送和接收的程序。
消息(message)是一个格式化的可变长的信息单元。消息机制允许由一个进程给其它任意的进程发送一个消息。当一个进程收到多个消息时,可将它们排成一个消息队列。消息使用二种重要的数据结构:一是消息首部,其中记录了一些与消息有关的信息,如消息数据的字节数;二个消息队列头表,其每一表项是作为一个消息队列的消息头,记录了消息队列的有关信息。
6、进程的共享存储区通信
编制一长度为1k的共享存储区发送和接收的程序。
(1)共享存储区机制的概念
共享存储区(Share Memory)是UNIX系统中通信速度最高的一种通信机制。该机制可使若干进程共享主存中的某一个区域,且使该区域出现(映射)在多个进程的虚地址空间中。另一方面,一个进程的虚地址空间中又可连接多个共享存储区,每个共享存储区都有自己的名字。当进程间欲利用共享存储区进行通信时,必须先在主存中建立一共享存储区,然后将它附接到自己的虚地址空间上。此后,进程对该区的访问操作,与对其虚地址空间的其它部分的操作完全相同。进程之间便可通过对共享存储区中数据的读、写来进行直接通信。图示列出二个进程通过共享一个共享存储区来进行通信的例子。其中,进程A将建立的共享存储区附接到自己的AA’区域,进程B将它附接到自己的BB’区域。

实验中用到的系统调用函数

Fork, exec, wait, exit, getpid, sleep, lockf, kill, signal, read, write, msgget, msgsnd, msgrcv, msgctl,shmget, shmat, shmdt, shmctl。

实验步骤

实验1、编写段程序,使用系统调用fork( )创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程并发执行,观察实验结果并分析原因。
父进程创建子进程P1和P2,父进程输出’a’,子进程P1输出’b’,子进程P2输出’c’。代码如下:

//1.1.c
#include<stdio.h>
#include<unistd.h>
void main()
{
   
	int p1,p2;
	while((p1=fork())==-1);
	if(p1==0) /*子进程1 */
		printf("b");
	else
	{
   
		while((p2=fork())==-1);
		if(p2==0) /*子进程2 */
			printf("c");
		else /*父进程 */
			printf("a");
	}
}

代码分析:
首先创建p1,当创建成功时p1有两个值。0和大于0,如果p1等于0,就在子进程状态运行,这时候p1输出b,否则就是大于0,大于0就是指在父进程中,在父进程状态下,又创建一个子进程P2,同理如果p2=0,在自进程状态下,那么输出c,如果p2大于0,则在父进程中,则输出a。
多次实验结果截图如下:

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
运行结果:
如上图所示,经过多次实验,结果显示大多数输出顺序是abc,但是也存在输出顺序为:abc, acb, bca, bac …

结果分析:
系统中存在main父进程,子进程p1,子进程p2和shell进程,这四个进程处于并发状态。实质上这四个进程都在输出,都在争夺屏幕的输出资源,这三个进程并发执行,由于并没有对这四个进程输出结果进行控制,所以输出a、b、c的顺序就不确定,这就是多进程运行的时候结果的不确定性。

思考题
(1) 、系统是怎样创建进程的?

这里我记得老师说过使用dmesg命令可以查看fork()函数执行的相关信息,但是我不会用
//1.2c
#include<stdio.h>
#include<unistd.h>
void main()
{
   
	int p1,p2;
	while((p1=fork())==-1);
	system("dmesg -T ");
	//execle("/usr/bin/dmesg","dmesg -T|grep redis",NULL,NULL);
	//execlp(prgname, prgname, 0);//Load the program
	//system("ps ax");
	//system("pstree");
	//system("trace -f -i -S ./executable-file-name");
	//strace -f -o ./1.2.txt 1.2
	//ltrace -f -i -S ./1.2
	if(p1==0) /*子进程1 */
		printf("b:%d",getpid());
	else
	{
   
		while((p2=fork())==-1);
		
		if(p2==0) /*子进程2 */
			
			printf("c:%d",getpid());
		else /*父进程 */
			printf("a:%d",getpid());
	}
}

在上面1.1.c程序的基础上,在调用fork()函数后,使用dmesg命令。结果没有找到fork()函数执行的流程。只能看到显示开机信息。
在这里插入图片描述
系统创建进程的过程

  1. 申请空白PCB(进程控制块)。
  2. 为新进程分配资源。
  3. 初始化PCB。
  4. 就新进程插入就绪队列。

(2) 、当首次调用新创建进程时,其入口在哪里?

//1.3.c
#include<stdio.h>
#include<unistd.h>
void main()
{
   
	int p1,p2;
	printf("Entrance 1, (pid:%d)\n", getpid());
	
	while((p1=fork())==-1);
	printf("Entrance 2, (pid:%d)\n", getpid());
	
	if(p1==0) /*子进程1 */
		printf("b:%d\n",getpid());
	else
	{
   
		while((p2=fork())==-1);
		if(p2==0) /*子进程2 */
			printf("c:%d\n",getpid())
  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值