上海大学操作系统实验六Word文档格式.docx
《上海大学操作系统实验六Word文档格式.docx》由会员分享,可在线阅读,更多相关《上海大学操作系统实验六Word文档格式.docx(37页珍藏版)》请在冰豆网上搜索。
解释一下。
1839
2247
224822522254
224922512253
2250
每一次运行返回的进程号都不相同,但是都符合家族进程树,出现这样的情况是由于系统本身就是随机分配进程号的。
②修改程序,使运行结果呈单分支结构,即每个父进程只产生一个子进程。
画出进程树,解释该程序。
用一个break;
语句使父进程在子进程结束后跳出循环,运行结果如下:
进程家族树如下:
2004
2401
2402
2403
2404
4.编写程序。
使用fork()和exec()等系统调用创建三个子进程。
子进程分别启动不同程序,并结束。
反复执行该程序,观察运行结果,结束的先后,看是否有不同次序。
编译代码如下:
子进程运行其它程序后,进程运行环境怎样变化的?
反复运行此程序看会有什么情况?
子进程运行其他程序后,这个进程就完全被新程序代替。
由于并没有产生新进程所以进程标识号不改变,除此之外的旧进程的其他信息,代码段,数据段,栈段等均被新程序的信息所代替。
新程序从自己的main()函数开始进行。
反复运行此程序发现结束的先后次序是不可预知的,每次运行结果不一样。
原因是当每个子进程运行其他程序时,他们的结束随着其他程序的结束而结束,所以结束的先后次序在改变。
5.编译程序,验证子进程继承父进程的程序、数据等资源。
如用父、子进程修改公共变量和私有变量的处理结果;
父、子进程的程序区和数据区的位置。
编译源代码如下:
子进程被创建后,对父进程的运行环境有影响吗?
子进程被创建后,对父进程的运行环境无影响,因为当子进程在运行时,他有自己的代码段和数据段,这些都可以作修改,但是父进程的代码段和数据段是不会随着子进程数据段和代码段的改变而改变。
6.参照《实验指导》第五部分中“管道操作的系统调用”。
复习管道通信概念,编写一个程序。
父进程创建两个子进程,父子进程之间利用管道进行通信。
要求能显示父进程、子进程各自的信息,体现通信效果。
源代码:
①什么是管道?
进程如何利用它进行通信的?
解释一下实现方法。
②修改睡眠时机、睡眠长度,看看会有什么变化。
请解释。
③加锁、解锁起什么作用?
不用它行吗?
1.管道是指能够连接一个写进程和一个读进程,并允许他们以生产者-消费者方式进行通信的一个共享文件,又称pipe文件。
由写进程从管道的入端将数据写入管道,而读进程则从管道出端读出数据来进行通信。
2.修改睡眠时机和睡眠长度都会引起进程被唤醒的时间不一,因为睡眠时机决定进程在何时睡眠,睡眠长度决定进程何时被唤醒。
3.加锁、解锁是为了解决临界资源的共享问题。
不用它将会引起无法有效管理数据,即数据会被修改导致读错了数据。
7.编程验证:
实现父子进程通过管道进行通信。
进一步编程,验证子进程结束,由父进程执行撤消进程的操作。
测试父进程先于子进程结束时,系统如何处理“孤儿进程”的。
把上题中的父进程中的wait()都去掉,运行结果如下:
对此作何感想,自己动手试一试?
解释一下你的实现方法。
答:
只要在父进程后加上wait()函数,然后打印“子进程已经结束”,一旦子进程结束,父进程撤销进程。
把父进程中的wait()去掉,父进程先于子进程终止时.所有子进程的父进程改变为init进程,称为进程由init进程领养。
8.编写两个程序一个是服务者程序,一个是客户程序。
执行两个进程之间通过消息机制通信。
消息标识MSGKEY可用常量定义,以便双方都可以利用。
客户将自己的进程标识(pid)通过消息机制发送给服务者进程。
服务者进程收到消息后,将自己的进程号和父进程号发送给客户,然后返回。
客户收到后显示服务者的pid和ppid,结束。
运行结果:
服务者:
客户程序:
想一下服务者程序和客户程序的通信还有什么方法可以实现?
解释一下你的设想,有兴趣试一试吗。
还可以用信号量机制来实现。
信号量是一个整形计数器,用来控制多个进程对共享资源的访问。
或者通过消息队列信号机制,通过向消息队列发送信息、接收信息来实现进程间的通信。
9.这部分内容涉及《实验指导》第五部分中“有关信号处理的系统调用”。
编程实现软中断信号通信。
父进程设定软中断信号处理程序,向子进程发软中断信号。
子进程收到信号后执行相应处理程序。
源代码如下:
这就是软中断信号处理,有点儿明白了吧?
讨论一下它与硬中断有什么区别?
看来还挺管用,好好利用它。
硬中断是由外部硬件产生的,而软中断是CPU根据软件的某条指令或者软件对标志寄存器的某个标志位的设置而产生的。
10.怎么样,试一下吗?
用信号量机制编写一个解决生产者—消费者问题的程序,这可是受益匪浅的事。
本《实验指导》第五部分有关进程通信的系统调用中介绍了信号量机制的使用。
#include<
stdio.h>
stdlib.h>
unistd.h>
pthread.h>
semaphore.h>
signal.h>
#defineN5//消费者或者生产者的数目
#defineM10//缓冲数目
//intM=10;
intin=0;
//生产者放置产品的位置
intout=0;
//消费者取产品的位置
intbuff[M]={0};
//缓冲初始化为0,开始时没有产品
sem_tempty_sem;
//同步信号量,当满了时阻止生产者放产品
sem_tfull_sem;
//同步信号量,当没产品时阻止消费者消费
pthread_mutex_tmutex;
//互斥信号量,一次只有一个线程访问缓冲
intproduct_id=0;
//生产者id
intprochase_id=0;
//消费者id
//信号处理函数
voidHandlesignal(intsigno){
printf("
程序退出\n"
signo);
exit(0);
}
/*打印缓冲情况*/
voidprint(){
inti;
产品队列为"
);
for(i=0;
i<
M;
i++)
%d"
buff[i]);
\n"
/*生产者方法*/
void*product(){
intid=++product_id;
while
(1){//重复进行
//用sleep的数量可以调节生产和消费的速度,便于观察
sleep
(2);
sem_wait(&
empty_sem);
pthread_mutex_lock(&
mutex);
in=in%M;
生产者%d在产品队列中放入第%d个产品\t"
id,in);
buff[in]=1;
print();
++in;
pthread_mutex_unlock(&
sem_post(&
full_sem);
}
/*消费者方法*/
void*prochase(){
intid=++prochase_id;
sleep(5);
out=out%M;
消费者%d从产品队列中取出第%d个产品\t"
id,out);
buff[out]=0;
++out;
intmain(){
生产者和消费者数目都为5,产品缓冲为10,生产者每2秒生产一个产品,消费者每5秒消费一个产品,Ctrl+退出程序\n"
pthread_tid1[N];
pthread_tid2[N];
intret[N];
//结束程序
if(signal(SIGINT,Handlesignal)==SIG_ERR){//按ctrl+C产生SIGINT信号
信号安装出错\n"
//初始化同步信号量
intini1=sem_init(&
empty_sem,0,M);
//产品队列缓冲同步
intini2=sem_init(&
full_sem,0,0);
//线程运行同步
if(ini1&
&
ini2!
=0){
信号量初始化失败!
exit
(1);
//初始化互斥信号量
intini3=pthread_mutex_init(&
mutex,NULL);
if(ini3!
线程同步初始化失败!
//创建N个生产者线程
N;
i++){
ret[i]=pthread_create(&
id1[i],NULL,product,(void*)(&
i));
if(ret[i]!
生产者%d线程创建失败!
i);
//创建N个消费者线程
id2[i],NULL,prochase,NULL);
消费者%d线程创建失败!
//等待线程销毁
pthread_join(id1[i],NULL);
pthread_join(id2[i],NULL);
五.研究并讨论
1.讨论Linux系统进程运行的机制和特点,系统通过什么来管理进程?
在Linux中,每个进程在创建时都会被分配一个数据结构,称为进程控制块(ProcessControlBlock,简称PCB)。
PCB中包含了很多重要的信息,供系统调度和进程本身执行使用。
所有进程的PCB都存放在内核空间中。
PCB中最重要的信息就是进程PID,内核通过这个PID来唯一标识一个进程。
PID可以循环使用,最大值是32768。
init进程的pid为1,其他进程都是init进程的后代。
除了进程控制块(PCB)以外,每个进程都有独立的内核堆栈(8k),一个进程描述符结构,这些数据都作为进程的控制信息储存在内核空间中;
而进程的用户空间主要存储代码和数据。
Linux操作系统使用一些系统调用(如:
fork()、wait、exit等)来实现对进程的管理。
2.C语言中是如何使用Linux提供的功能的?
用程序及运行结果举例说明。
C语言是通过在.c文件中添加函数调用的.h文件,来调用进程管理的相关函数,并通过getpid()和getppid()来查看Linux系统为每个进程分配的进程号。
如下图:
父进程通过循环语句创建若干子进程,输出打印每一个进程的进程号,我们就可以通过进程号画出家族数。
3.什么是进程?
如何产生的?
举例说明。
进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。
它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
引起进程创建的事件有用户登录、作业调度、提供服务和应用请求。
一旦操作系统发现了要求创建新进程的事件后,便调用进程创建原语Creat()按下述步骤创建一个新进程。
申请空白PCB、为新进程分配资源、初始化进程控制块、将新进程插入就绪队列
例如用户登入,在分时系统中,用户在终端键入登录命令后,如果是合法用户,系统将为该终端建立一个进程,并把它插入就绪队列中。
4.进程控制如何实现的?
进程控制一般是由OS的内核中的原语来实现的。
例子:
唤醒原语wakeup()
当被阻塞进程所期待的事件出现时,如I/O完成或其所期待的数据已经到达,则由有关进程(比如用完并释放了该I/O设备的进程)调用唤醒原语wakeup(),将等待该事件的进程唤醒。
唤醒原语执行的过程是:
首先把被阻塞的进程从等待该事件的阻塞队列中移出,将其PCB中的现行状态由阻塞改为就绪,然后再将该PCB插入到就绪队列中。
5.进程通信方式各有什么特点?
进程间通信可分为4种形式:
(1)主从式:
①主进程可自由地使用从进程的资源或数据;
②从进程的动作受主进程的控制;
③主进程和从进程的关系是固定的。
(2)会话式:
①使用进程在使用服务进程所提供的服务之前,必须得到服务进程的许可;
②服务进程根据使用进程的要求提供服务,但对所提供服务的控制由服务进程自身完成。
③使用进程和服务进程在通信时有固定连接关系。
(3)消息或邮箱机制:
①只要存在空缓冲区或邮箱,发送进程就可以发送消息。
②与会话系统不同,发送进程和接收进程之间无直接连接关系,接收进程可能在收到某个发送进程发来的消息之后,又转去接收另一个发送进程发来的消息。
③发送进程和接收进程之间存在缓冲区或邮箱用来存放被传送消息。
(4)共享存储区方式:
诸进程可通过对共享存储区中数据的读或写来实现通信。
进程在通信前,先向系统申请获得共享存储区中的一个分区,并指定该分区的关键字;
若系统已经给其他进程分配了这样的分区,则将该分区的描述符返回给申请者。
③由申请者把获得的共享存储分区连接到本进程上。
可像读、写普通存储器一样地读、写该公用存储分区。
以下是管道通信的程序说明和代码实现:
程序运行结果:
6.管道通信如何实现?
该通信方式可以用在何处?
向管道(共享文件)提供输入的发送进程(即写进程),以字符流形式将大量的数据送入管道;
而接受管道输出的接收进程(即读进程),则从管道中接收(读)数据。
这种通信方式用于数据传输、资源共享和事件通知。
7.什么是软中断?
软中断信号通信如何实现?
软中断是利用硬件中断的概念,用软件方式进行模拟,实现宏观上的异步执行效果。
利用signal和kill实现软中断通信:
kill(pid,signal):
向进程pid发送信号signal,若pid进程在可中断的优先级(低优先级)上睡眠,则将其唤醒。
signal(sig,ps):
设置sig号软中断信号的处理方式;
三种处理方式:
SIG_DFL:
系统默认方式,一般是终止进程;
SIG_IGN:
忽略(屏蔽);
func():
用制定义函数func()处理。
Signal设置的处理方式,仅一次有效,处理后即回到默认方式。
9(SIGKILL)号软中断不允许设置。
六.体会
在本次进程管理和进程通信的实验中,我学会了用vim文本编译器编写C语言实现进程的管理和进程之间的通信,并编译和运行工程文件。
掌握了如何创建子进程,理解了子进程与父进程之间的关系,实现管道通信和软中断信号通信,对一些必要的基础函数的调用能够识别和运用。
实验六SHELL编程
掌握vi的三种工作方式,熟悉vi编辑程序的使用。
学习Shell程序设计方法。
掌握编程要领。
复习操作系统课程相关的用户接口概念。
熟悉本《实验指导》第三、四部分。
三.实验内容
学习使用vi编辑程序。
编写Shell程序。
将程序文件设置为可执行文件(用chmod命令)。
在命令行方式中运行Shell程序。
四.实验步骤
1.按本《实验指导》第三部分的内容。
熟悉vi的三种工作方式。
熟悉使用各种编辑功能。
.
试一试vi的三种工作方式各用在何时?
用什么命令进入插入方式?
怎样退出插入方式?
文件怎样存盘?
注意存盘后的提示信息。
①三种工作方式的使用时机:
插入方式
进入插入方式,屏幕下方有一行“------Insert------”字样表示。
需要输入文本的内容时用到插入方式,可以用退格键来纠正错误。
在插入方式中按一下<
ESC>
,即退出插入方式,进入转义命令方式。
转义命令方式
刚进入vi或退出插入方式,即为转义命令方式。
这时键入的任何字符转义为特殊功能,如:
移动、删除、替换等。
大多数转义命令由一个或两个字母组成,操作时没有提示符,而且输入命令不需要按<
ENTER>
。
末行命令方式
在转义命令方式中,按冒号“:
”进入末行命令方式。
屏幕最末一行的行首显示冒号作为命令提示。
命令行输入后按<
开始执行。
此时用户可进行文件的全局操作,如:
全局查找、替换、文件读、写等。
②用什么命令进入插入方式:
用户输入命令功能描述
itext<
在光标前插入新文本,ENTER可重起一行
Itext<
在当前行起始处插入新文本
atext<
在光标后输入新的文本
Atext<
在当前行末尾输入新的文本
otext<
在当前行下产生新的一行并输入文本
Otext<
在当前行上产生新的一行并输入文本
③怎样退出插入方式:
,即退出插入方式,进入转义命令方式。
④文件怎样存盘:
存盘过程只需键入命令:
:
w
命令w将文件以当前名字存入磁盘,并覆盖了文件先前的副本。
但w命令不影响缓冲区的内容。
如果要将文件以不同的名字保存,例如newfile,需键入命令:
wnewfile
如果不存在名为newfile的文件,vi编辑器将存入文件并给出文件的大小。
如果这个文件已经存在,那么vi会通知你,但并不刷新文件的内容。
如果想刷新已存在的文件的内容,则可键入命令:
w!
newfile
同样,感叹号“!
”放弃了标准的vi防止覆盖文件的保护功能,强制刷新。
2.创建和执行Shell程序
用前面介绍的Vi或其他文本编辑器编写Shell程序,并将文件以文本文件方式保存在相应的目录中。
用chmod将文件的权限设置为可执行模式,如若文件名为shdemo.h,则命令如下:
$chmod755shdemo.h(文件主可读、写、执行,同组人和其他人可读和执行)在提示符后执行Shell
程序:
$shdemo.h(直接键入程序文件名执行)
或$shshdemo.h(执行Shell程序)
或$.shdemo.h(没有设置权限时可用点号引导)
用vim编译程序:
运行结果如下:
3.用vi编写《实验指导》“第四部分Shell程序设计”中的例1
(假设文件为prog1.h),练习内部变量和位置参数的用法。
用vim编译程序如下:
用chmod将文件的权限设置为可执行模式,并在提示符后键入命令行:
$./prog1.#没有参数
或$shprog1.
屏幕显示:
Namenotprovided
在提示符后键入命令行:
$./prog1.hTheodore#有一个参数
YournameisTheodore#引用$1参数的效果
4.进一步修改程序prog1.h,要求显示参数个数、程序名字,并逐个显示参数。
修改后的程序如下:
运行如下:
5.修改例1程序(即上面的prog1.h),用read命令接受键盘输入。
若没有输入显示第一种提示,否则第二种提示。
6.用vi编写《实验指导》“第四部分Shell程序设计”中的例2、例3,练习字符串比较运算符、数据比较运算符和文件运算符的用法,观察运行结果。
例2的运行结果如下:
例3:
设当前目录下有一个文件filea,控制权为(~r–xr–xr–x即0751),有一个子目录cppdir,控制权为(drwxrwxrwx)程序compare2.h中有如下内容:
7.修改例2程序,使在程序运行中能随机输入字符串,然后进行字符串比较。
编译程序:
8.修改例3程序,使在程序运行中能随机输入文件名,然后进行文件属性判断。
9.用vi编写《实验指导》“第四部分Shell程序设计”中的例4、例5、例6、例7,掌握控制语句的用法,观察运行结果。
例4:
例5:
例6:
例7:
10.