山东大学操作系统实验报告.docx

上传人:b****5 文档编号:8050052 上传时间:2023-01-28 格式:DOCX 页数:57 大小:1.03MB
下载 相关 举报
山东大学操作系统实验报告.docx_第1页
第1页 / 共57页
山东大学操作系统实验报告.docx_第2页
第2页 / 共57页
山东大学操作系统实验报告.docx_第3页
第3页 / 共57页
山东大学操作系统实验报告.docx_第4页
第4页 / 共57页
山东大学操作系统实验报告.docx_第5页
第5页 / 共57页
点击查看更多>>
下载资源
资源描述

山东大学操作系统实验报告.docx

《山东大学操作系统实验报告.docx》由会员分享,可在线阅读,更多相关《山东大学操作系统实验报告.docx(57页珍藏版)》请在冰豆网上搜索。

山东大学操作系统实验报告.docx

山东大学操作系统实验报告

操作系统实验报告

 

计算机科学与技术学院

一、进程控制实验

1.1实验目的

加深对于进程并发执行概念的理解。

实践并发进程的创建和控制方法。

观察和体验进程的动态特性。

进一步理解进程生命期期间创建、变换、撤销状态变换的过程。

掌握进程控制的方法,了解父子进程间的控制和协作关系。

练习Linux系统中进程创建与控制有关的系统调用的编程和调试技术。

1.2示例实验

1.2.1实验内容

以下实验示例程序应实现一个类似shell子命令的功能,它可以从执行程序中启动另一个新的子进程并执行一个新的命令和其并发执行。

1.2.2实验演示结果

1.3独立实验

1.3.1实验内容

参考以上示例程序中建立并发进程的方法,编写一个父子协作进程,父进程创建一个子进程并控制它每隔3秒显示一次当前目录中的文件名列表。

1.3.2实验步骤 

1.3.2.1算法设计

通过进程间的通讯,先创建一个父进程一个子进程,父进程沉睡3秒,子进程作为当前父进程再次创建一个他的子进程,当前子进程执行显示当前目录文件列表功能,执行execve()方法后死亡。

While

(1) 在死循环里无限进行当前操作。

即达到父进程创建一个子进程并控制它每隔3秒显示一次当前目录中的文件名列表的要求。

1.3.2.2开发调试过程

打开一终端命令行窗体,新建一个文件夹,在该文件夹中建立名为pctrl.c的C语言程序;

再建立以下名为pctrl.h的C语言头文件;

建立项目管理文件Makefile;

输入make命令编译连接生成可执行的pctl程序;

执行pctl程序;

再次执行带有子进程指定执行命令的pctl程序。

1.3.2.3思考与分析

1.反映的进程的特征和功能,在真实的操作系统中是怎样实现和反映出教材中讲解的进程的生命期、进程的实体和进程状态控制的。

对于进程概念和并发概念有哪些新的理解和认识?

子进程是如何创建和执行新程序的?

答:

进程是一个可并发执行的程序在某数据集上的一次运行,是程序的一次运行过程。

而程序只是进程的一个组成部分,进程是程序的执行过程。

程序是静态的指令集合,而进程是动态的过程实体,是动态的产生、发展和消失。

此外所谓的进程并发执行是在宏观上并发,而在微观上交替执行。

每个进程都用一个唯一的整数形式的进程标识符来标识,通过fork()系统调用,可创建新进程。

新进程通过复制原来进程的地址空间而成。

这种机制允许父子进程方便的进行通信。

系统调用fork(),得到的子进程实际上是父进程的克隆体,要执行不同的新程序要使用系统调用exec(),以用新程序来取代进程的内存空间。

其功能是根据参数指定的文件名找到程序文件,把它装入内存,覆盖原来进程的映像,形成一个不同于父进程的子进程。

除了进程映像被更换之外,新进程的PID及其他PCB属性均保持不变,实际上是一个新进程“借壳”原来子进程开始运行。

父进程可通过系统调用waitpid()来把自己移出就绪队列来等待子进程的终止。

2.信号的机理是什么?

怎样利用信号实现进程控制?

每个信号对应一个正整数常量(为signal number。

定义在系统头文件中),代表同一用户的诸进程之间传送事先约定的信息的类型,用于通知某进程发生了某异常事件。

每个进程运行时,要通过信号机制来检查是否有信号到达。

若有,中断正在执行的程序,转向该信号相对应的处理程序,已完成对事件的处理;处理结束后再返回到原来的断点继续执行。

1.3.3实验演示结果

1.3.4实验代码

pctl.c文件:

#include"pctl.h"

intmain()

{

intpid_1,pid_2;//存放子进程号

intstatus_1,status_2;//存放子进程返回状态

while

(1){

pid_1=fork();

if(pid_1<0)//建立子进程失败?

{

printf("CreateProcessfail!

\n");

exit(EXIT_FAILURE);

}

if(pid_1==0)//子进程执行代码段

{

//报告父子进程进程号

printf("IamChild-lsprocess%d\nMyfatheris%d\n",getpid(),getppid());/*getpid返回当前进程的进程号,getppid返回当前进程父进程的进程号*/

pid_2=fork();

if(pid_2<0)//建立子进程失败?

{

printf("CreateProcessfail!

\n");

exit(EXIT_FAILURE);

}

if(pid_2==0)//子进程执行代码段

{//报告父子进程进程号

printf("IamChild-psprocess%d\nMyfatheris%d\n",getpid(),getppid());

printf("%dchildwillRunning:

\n",getpid());/*子进程被键盘中断信号唤醒继续执行*/

status_2=execve("/bin/ps",NULL,NULL);//装入并执行新的程序

}else{

printf("waitfortheps-childend%d\n",pid_2);

waitpid(pid_2,&status_2,0);//等待子进程2结束

//status用于保留子进程的退出状态

}

printf("%dchildwillRunning:

\n",getpid());//装入并执行新的程序

char*argv[]={"0",NULL};

status_1=execve("/bin/ls",argv,NULL);

}

else{

printf("IamParentprocess%d\n",getpid());

printf("waitforthels-childend%d\n",pid_1);

waitpid(pid_1,&status_1,0);

printf("childend,sleep...\n");

sleep(3);//sleep函数会令调用进程的执行挂起睡眠3秒

}

}

returnEXIT_SUCCESS;

}

pctl.h文件:

#include

#include

#include

#include

#include

#include

//进程自定义的键盘中断信号处理函数

typedefvoid(*sighandler_t)(int);

voidsigcat(){

printf("%dProcesscontinue\n",getpid());

}

二、进程调度算法实验

2.1实验目的

加深对进程调度概念的理解,体验进程调度机制的功能,了解Linux系统中进程调度策略的使用方法。

练习进程调度算法的编程和调试技术。

2.2示例实验

2.2.1实验内容

以下示例实验程序要测试在linux系统中不同调度策略和不同优先数的调度效果。

2.2.2实验演示结果

2.3独立实验

2.3.1实验内容

设有两个并发执行的父子进程,不断循环输出各自进程号、优先数和调度策

略。

进程初始调度策略均为系统默认策略和默认优先级。

当某个进程收到SIGINT

信号时会自动将其优先数加1,收到SIGCSTP信号时会自动将其优先数减1。

请编

程实现以上功能。

2.3.2实验步骤

2.3.2.1算法设计

建立一个父进程和一个子进程。

通过第一章学习的进程控制相互发送信号。

当按下Ctrl+C时,父进程实现优先级加1。

当按下Ctrl+Z时,子进程实现优先级减1。

用signal系统调用将父进程注册一个本进程处理SIGINT的实现优先级加1的函数。

子进程注册一个本进程处理SIGTSTP的实现优先级减1的函数。

当按下Ctrl+Z时,子进程做出响应,其优先级减1;当按下Ctrl+C时,父进程做出响应,父进程优先级加1.然后再输出各自进程号、优先数和调度策略。

以上行为通过for()语句循环。

2.3.2.2开发调试过程

新建一个文件夹,在该文件夹中建立以下名为pctl.c的C语言程序。

再建立以下名为pctl.h的C语言头文件。

建立项目管理文件Makefile。

输入make命令编译连接生成可执行的pctl程序。

执行并调试pctl程序

2.3.2.3思考与分析

进程调度调度策略和功能如下所示:

SCHED_OTHER默认的分时调度策略(值等于0)

SCHED_FIFO先进先先出调度策略(值等于1)

SCHED_RR时间片轮转调度策略(值等于2)

进程调度本质就是让谁先执行,让谁后执行。

在真实的操作系统中,由调度策略和优先级决定谁先执行。

Linux的调度策略有三种,SCHED_OTHER分时调度,SCHED_FIFO先进先出,SCHED_RR时间片轮转。

后两种专用于对响应时间有特殊要求的进程,并且会抢先于SCHED_OTHER调度策略的进程而执行。

通过这个系统调用设置进程调度策略,intsched_setscheduler(pid_tpid,intpolicy,conststructsched_param*sp);其中pid是进程号,policy是以上说明的3种调度策略之一,sp调度参数结构指针,调度参数结构主要存有调度优先数。

进程优先数(prio)由静态优先级和动态优先级两部分组成。

静态优先级与调度策略有关。

动态优先级由以下系统调用设置,intsetpriority(intwhich,intwho,intprio);which设置的对象。

可以是:

进程PRIO_PROCESS

进程组PRIO_PGRP

用户PRIO_USER

who对应设置对象的进程号或组号或用户号

prio要设置的进程优先数

2.3.3实验演示结果

2.3.4实验代码

psched.c文件:

#include

#include

#include

#include

#defineSIGINT2

#defineSIGTSTP20

voidhandler_sigint(intsigno){//用于提升优先数

printf("\n%d进程优先数增加1\n",getpid());

setpriority(PRIO_PROCESS,getpid(),

getpriority(PRIO_PROCESS,getpid())+1);

}

voidhandler_sigtstp(intsigno){//用于降低优先数

printf("\n%d进程优先数减小1\n",getpid());

setpriority(PRIO_PROCESS,getpid(),

getpriority(PRIO_PROCESS,getpid())-1);

}

intmain(){

pid_tpid;

if((pid=fork())<0){

perror("processcreateerror!

");

}

if(pid>0){

signal(SIGINT,handler_sigint);//父进程处理Ctrl+C

signal(SIGTSTP,SIG_IGN);//忽略Ctrl+Z

}else{

setpriority(PRIO_PROCESS,getpid(),10);//设定子进程初始动态优先级为10,否则看不出效果

signal(SIGTSTP,handler_sigtstp);//子进程处理Ctrl+Z

signal(SIGINT,SIG_IGN);//忽略Ctrl+C

}

inti=1;

while(i<=20){

if(pid>0){

printf("I'mparentprocess,");

}else{

printf("I'mchildprocess,");

}

printf("pid=%d,priority=%d,scheduler=%d\n",

getpid(),getpriority(PRIO_PROCESS,

getpid()),sched_getscheduler(getpid()));

sleep(3);

i++;

}

}

其他文件同示例实验。

二、进程同步实验

3.1实验目的

加深对并发协作进程同步与互斥概念的理解,观察和体验并发进程同步与互斥操作的效果,分析与研究经典进程同步与互斥问题的实际解决方案。

了解Linux系统中IPC进程同步工具的用法,练习并发协作进程的同步与互斥操作的编程与调试技术。

3.2示例实验

3.2.1实验内容

以下示例实验程序应能模拟多个生产/消费者在有界缓冲上正确的操作。

它利用N个字节的共享内存作为有界循环缓冲区,利用写一字符模拟放一个产品,利用读一字符模拟消费一个产品。

当缓冲区空时消费者应阻塞睡眠,而当缓冲区满时生产者应当阻塞睡眠。

一旦缓冲区中有空单元,生产者进程就向空单元中入写字符,并报告写的内容和位置。

一旦缓冲区中有未读过的字符,消费者进程就从该单元中读出字符,并报告读取位置。

生产者不能向同一单元中连续写两次以上相同的字符,消费者也不能从同一单元中连续读两次以上相同的字符。

3.2.2实验演示结果

3.3独立实验

3.3.1实验内容

抽烟者问题。

假设一个系统中有三个抽烟者进程,每个抽烟者不断地卷烟并抽烟。

抽烟者卷起并抽掉一颗烟需要有三种材料:

烟草、纸和胶水。

一个抽烟者有烟草,一个有纸,另一个有胶水。

系统中还有两个供应者进程,它们无限地供应所有三种材料,但每次仅轮流提供三种材料中的两种。

得到缺失的两种材料的抽烟者在卷起并抽掉一颗烟后会发信号通知供应者,让它继续提供另外的两种材料。

这一过程重复进行。

请用以上介绍的IPC同步机制编程,实现该问题要求的功能。

3.3.2实验步骤

3.3.2.1问题分析

有两个供应者,有三个消费者。

用于存放烟草,纸和胶水的公共缓冲区的大小是3.存放顺序要指定。

分别是烟草,纸和胶水。

每一个供应者供应的物品有三种,(烟草+纸)(烟草+胶水)(纸+胶水)。

三个消费者分别需要三个里面的一种。

约束:

(1)某一时刻,只能有一个供应者,放入一对物品。

(2)某一时刻,只能有一个消费者,且要保证这个消费者恰好需要的就是刚刚生产的物品。

(3)所有供应者提供这种物品之后,不论它要生产什么物品,只有等到消费者拿走了物品之后,才能继续生产。

3.3.2.2算法设计

(1)供应者的上下文完全一样,在程序中fork()子进程之后,让父进程和子进程并发执行供应者代码即可。

(2)消费者有三个,且每个消费者需要的物品不同,所以不能使用同一个代码段。

这样,就需要建立两个子进程和一个父进程同时并发执行。

然后在各自区域执行相似的但不同的代码段。

(3)用信号灯实现同步和互斥约束。

(4)创建公共缓冲区和指向首地址的指针

//获取缓冲区使用的共享内存,buff_ptr指向缓冲区首地址

buff_ptr=(char*)set_shm(buff_key,buff_num,shm_flg);

//获取供应者放产品首位置指针pput_ptr

pput_ptr=(int*)set_shm(pput_key,pput_num,shm_flg);

3.3.2.3开发调试过程

新建一个文件夹,在该文件夹中建立以下名为ipc.h的C语言头文件。

再建立以下名为ipc.c的C语言头文件,实现头文件中申明的函数。

再建立以下名为producer.c的C语言头文件,实现供应者的功能。

再建立以下名为consumer.c的C语言头文件,实现消费者的功能。

建立项目管理文件Makefile。

输入make命令编译连接生成可执行的producer和consumer程序。

执行并调试producer和consumer程序。

3.3.2.4思考与分析

进程之间的同步在该实验中是通过信号灯实现的。

进程之间为了同步而使用的信号灯,必须完全相同的在各自进程中创建。

这样,这些信号灯就会被这些进程共享。

然后通过执行信号灯的up()和down()操作.使得进程并发执行时保持同步。

因为如果信号灯的值小于0,那么这个进程会阻塞,这就是为什么能够同步。

操作系统中,进程同步可以通过信号量机制实现。

在本实验中,信号灯就是信号量,down()操作就是信号量的wait操作,up()操作就是信号量的signal操作。

3.3.3实验演示结果

3.3.4实验代码

ipc.h文件:

#include

#include

#include

#include

#include

#include

#include

#defineBUFSZ256

//建立或获取ipc的一组函数的原型说明

intget_ipc_id(char*proc_file,key_tkey);

char*set_shm(key_tshm_key,intshm_num,intshm_flag);

intset_msq(key_tmsq_key,intmsq_flag);

intset_sem(key_tsem_key,intsem_val,intsem_flag);

intdown(intsem_id);

intup(intsem_id);

typedefunionsemuns{

intval;

}Sem_uns;

typedefstructmsgbuf{

longmtype;

charmtext[1];

}Msg_buf;

//生产消费者共享缓冲区即其有关的变量

key_tbuff_key;

intbuff_num;

char*buff_ptr;

//生产者放产品位置的共享指针

key_tpput_key;

intpput_num;

int*pput_ptr;

//消费者取产品位置的共享指针

key_tcget_key;

intcget_num;

int*cget_ptr;

//生产者有关的信号量

key_tprod_key;

key_tpmtx_key;

intprod_sem;

intpmtx_sem;

//消费者有关的信号量

key_tc_PG_key;

key_tc_TP_key;

key_tc_TG_key;

key_tcmtx_key;

intc_PG_sem;

intc_TP_sem;

intc_TG_sem;

intcmtx_sem;

intsem_val;

intsem_flg;

intshm_flg;

 

ipc.c文件:

#include"ipc.h"

intget_ipc_id(char*proc_file,key_tkey)

{

FILE*pf;

inti,j;

charline[BUFSZ],colum[BUFSZ];

if((pf=fopen(proc_file,"r"))==NULL){

perror("Procfilenotopen");

exit(EXIT_FAILURE);

}

fgets(line,BUFSZ,pf);

while(!

feof(pf)){

i=j=0;

fgets(line,BUFSZ,pf);

while(line[i]=='')i++;

while(line[i]!

='')colum[j++]=line[i++];

colum[j]='\0';

if(atoi(colum)!

=key)continue;

j=0;

while(line[i]=='')i++;

while(line[i]!

='')colum[j++]=line[i++];

colum[j]='\0';

i=atoi(colum);

fclose(pf);

returni;

}

fclose(pf);

return-1;

}

intdown(intsem_id)

{

structsembufbuf;

buf.sem_op=-1;

buf.sem_num=0;

buf.sem_flg=SEM_UNDO;

if((semop(sem_id,&buf,1))<0){

perror("downerror");

exit(EXIT_FAILURE);

}

returnEXIT_SUCCESS;

}

intup(intsem_id)

{

structsembufbuf;

buf.sem_op=1;

buf.sem_num=0;

buf.sem_flg=SEM_UNDO;

if((semop(sem_id,&buf,1))<0){

perror("uperror");

exit(EXIT_FAILURE);

}

returnEXIT_SUCCESS;

}

intset_sem(key_tsem_key,intsem_val,intsem_flg)

{

intsem_id;

Sem_unssem_arg;

//测试由sem_key标识的信号灯数组是否已经建立

if((sem_id=get_ipc_id("/proc/sysvipc/sem",sem_key))<0)

{

//semget新建一个信号灯,其标号返回到sem_id

if((sem_id=semget(sem_key,1,sem_flg))<0)

{

perror("semaphorecreateerror");

exit(EXIT_FAILURE);

}

//设置信号灯的初值

sem_arg.val=sem_val;

if(semctl(sem_id,0,SETVAL,sem_arg)<0)

{

perror("semaphoreseterror");

exit(EXIT_FAILURE);

}

}

returnsem_id;

}

char*set_shm(key_tshm_key,intshm_num,intshm_flg)

{

inti,shm_id;

char*shm_buf;

//测试由s

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工作范文 > 行政公文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1