操作系统实验实验二三四.docx
- 文档编号:23349355
- 上传时间:2023-05-16
- 格式:DOCX
- 页数:17
- 大小:22.96KB
操作系统实验实验二三四.docx
《操作系统实验实验二三四.docx》由会员分享,可在线阅读,更多相关《操作系统实验实验二三四.docx(17页珍藏版)》请在冰豆网上搜索。
操作系统实验实验二三四
实验二进程管理设计
一.目的和要求
进程调度是处理机管理的核心内容。
本实验要求用C语言编写和调试一个简单的进程调度程序。
通过本实验可以加深理解有关进程控制块、进程队列的概念,并体会和了解优先数和时间片轮转调度算法的具体实施办法。
二.实验内容
1.设计进程控制块PCB表结构,分别适用于优先数调度算法和循环轮转算法。
PCB结构通常包括以下信息:
进程名、进程优先数(或轮转时间片)、进程所占用的CPU时间、进程的状态、当前队列指针等。
根据调度算法的不同,PCB结构的内容可以做适当的删除。
2.建立进程就绪队列,对两种不同算法编制入链子程序。
3.编制两种进程调度算法:
1)优先数调度;2)循环轮转调度。
三.实验环境
1.IBM286以上微型计算机及其兼容机。
2.DOS系统要求3.3及更高的版本。
3.TURBOC2.0。
四.实验要求
本实验要求用C语言编写,选用优先数算法和简单时间片轮转法对五个进程进行调度,每个进程可以有三种状态:
运行状态(RUN)、就绪状态(READY)和完成状态(FINISH)。
并假定初始状态为就绪状态。
五.模拟算法提示
1.数据结构
设计进程控制块结构如下:
PCB:
NAME
PRIO/ROUND
CPUTIME
COUNT
NEEDTIME
STATE
NEXT
其中:
NAME——进程标识符
PRIO——进程优先数
ROUND——进程轮转时间片
CPUTIME——进程占用CPU时间
COUNT——计数器
NEEDTIME——进程完成还要的CPU时间
STATE——进程的状态
NEXT——链指针
进程控制块链结构中主要指针如下:
RUN——当前运行进程指针
READY——就绪队列头指针
TAIL——就绪队列尾指针
FINISH——完成队列头指针
为了方便处理,程序中进程的运行时间以时间片为单位计算。
各进程的优先数或轮转时间片数以及进程需运行的时间片数的初值均由用户给定。
2.程序说明
1)在优先数算法中,进程每执行一次,优先数减3,CPU时间片数加1,进程还需要的时间片数减1。
在轮转法中,采用固定时间片,时间片数为2,进程每次执行一次,CPU时间片加2,进程还需要的时间片数减2,并排列就绪队列的尾上。
2)程序结构说明如下:
整个程序由FIRSTIN,INSERT1,INSERT2,PRINT,CREAT,PRISCH和ROUNDSCH函数组成。
其中:
INSERT1的功能是把还未完成且优先数小于别的进程的进程PCB按进程优先数的顺序插入到就绪队列中。
INSERT2是轮转法使用的函数,将执行了一个单位时间片数(为2)且还未完成的进程的PCB插到就绪队列的队尾。
FIRSTIN的功能是将就绪队列中的第一个进程投入运行。
PRINT打印每执行一个时间片后的所有进程的状态,这里,就绪(等待)用“W”代表。
CREATE的功能是创建新的进程,即创立进程的PCB,并将此PCB链入到就绪队列中去。
PRISCH按优先数算法调度进程。
ROUNDSCH按时间片轮转法调度进程。
主程序中定义了PCB的结构和其它变量:
number——进程数,algo为10个字符长的字符串,存放要求输入的算法的名,PRIORITY为优先数算法,ROUNDROBIN为循环轮转法,在程序运行时输入其中的一个。
3.主要算法
算法PRISCH
{while(当前运行进程不为空)
{
进程占用CPU时间加1
进程到完成还要的CPU时间减1
进程优先数减3
if(进程到完成还要的CPU时间为0)
{将该进程插入到完成队列中
修改该进程状态
当前运行进程指针为空
if(就绪队列不为空)
FIRSTIN函数
}
elseif(就绪队列不为空且当前进程优先数小于就绪队列中第一个进程的优先数)
{修改当前进程状态为W
INSERT1函数
FIRSTIN函数
}
PRINT函数
}
}
算法ROUNDSCH
{while(当前运行进程不为空)
{
进程占用CPU时间加1
进程到完成还要的CPU时间减1
进程计数器加1
if(进程到完成还要的CPU时间为0)
{将该进程插入到完成队列中
修改该进程状态
当前运行进程指针为空
if(就绪队列不为空)
FIRSTIN过程
}
elseif(进程计数器等于进程轮转时间片)
{修改当前进程计数器为0
if(就绪队列不为空)
{修改当前进程状态为W
INSERT2过程
FIRSTIN过程
}
}
PRINT过程
}
}
六.实验报告
1.实验题目。
2.采用的数据结构及符号说明。
3.打印一份源程序清单,并附加流程图与注释。
4.打印出两种算法的执行结果。
5.比较两种算法的优缺点并分析实验过程中遇到的问题,谈谈实验后的体会。
实验三
进入VI编辑器
格式:
vi文件名
例:
visy.c
Vi编辑器三种工作方式:
1.编辑方式:
进入VI处于编辑方式
2.文本输入方式:
在编辑方式下输入a,进入追加方式,输入i,进入插入方式
3.命令方式:
在输入方式下,按Esc键,由文本输入转向编辑方式,输入冒号:
进入命令方式
4.退出vi
:
wq写文件退出
:
wwenjianming写文件
:
q!
不写退出
:
wq!
写退出
编译c文件
Gcc-owenjianming.outwenjianming.c
运行文件:
./wenjianming.out
1.实验内容和目的
用vi编辑器编辑下列文件,使用gcc编译器和gdb调试器,对下列程序编译运行,分析运行结果。
要求至少完成3个程序。
2.程序示例
(1)/*父子进程之间的同步之例*/
#include
Main()
{
Intpid1;
If(pid1=fork())/*createchild1*/
{if(fork())/*createthechild2*/
{printf(“parent’scontext.\n”);
Printf(“parentiswaitingthechild1terminate.\n);
Wait(0);
Printf(“parentiswaitingthechild2terminate.\n”);
Wait(0);
Printf(“parentterminate.\n”);
Exit(0);
}
Else
/*child2*/
Printf(“child2’scontext.\n”);
Sleep(5);
Printf(“child2terminate.\n”);
Exit(0);
}
Else{if(pid1==0)/*child1*/
{printf(“child1’scontext.\n”);
Sleep(10);
Printf(“child1terminate.\n”);
Exit(0);
}
}
}
分析:
上述程序是父进程首先创建一个子进程,若成功,再创建另一个子进程,之后三个进程并发执行。
究竟谁先执行,是随机的,可根据执行结果判断。
试分析该程序的所有运行结果。
注释:
fork()调用正确完成时,给父进程返回地是被创建子进程的标识,给子进程返回的是0;创建失败时,返回给父进程的时-1;
Exit(0)进程终止自己
Wait(0)父进程同步等待子进程结束,即无子进程结束,父进程等待。
(2)管道通信机制
通过使用管道实现两个和多个进程之间的通信。
所谓管道,就是将一个进程的标准输出与另一个进程的标准输入联系在一起,进行通信的一种方法。
同组进程之间可用无名管道进行通信,不同组进程可通过有名管道通信。
使用无名管道进行父子进程之间的通信
#include
#include
#include
Intpipe(intfiledes[2]);
Charparent[]=”Amessagetopipe’communication.\n”;
Main()
{intpid,chan1[2];
Charbuf[100];
Pipe(chan1);
Pid=fork();
If(pid<0)
{printf(“tocreatechilderror\n”);
Exit
(1);
}
If(pid>0)
{close(chan1[0]);/*父进程关闭读通道*/
Printf(“parentprocesssendsamessagetochild.\n”);
Write(chan1[1],parent,sizeof(parent));
Close(chan1[1]);
Printf(“parentprocesswaitsthechildtoterminate.\n”);
Wait(0);
Printf(“parentprocessterminates.\n”);
}
Else{
Close(chan1[1]);/*子进程关闭写通道*/
Read(chan1[0],buf,100);
Printf(“themessagereadbychildprocessformparentis%s.\n”,buf);
Close(chan1[0]);
Printf(“childprocessterminates\n”);
}
}
观察运行结果。
注释:
pipe(intfiledes[2]):
创建一个无名管道,filedes[0]为读通道,filedes[1]为写通道。
(3)Linux中的多线程编程threads.c
#include
#include
#include
#include
#defineMAX10
pthread_tthread[2];
pthread_mutex_tmut;
intnumber=0,i;
void*thread1()
{
printf("thread1:
I'mthread1\n");
for(i=0;i { printf("thread1: number=%d\n",number); pthread_mutex_lock(&mut); number++; pthread_mutex_unlock(&mut); sleep (2); } printf("thread1: 主函数在等我完成任务吗? \n"); pthread_exit(NULL); } void*thread2() { printf("thread2: I'mthread2\n"); for(i=0;i { printf("thread2: number=%d\n",number); pthread_mutex_lock(&mut); number++; pthread_mutex_unlock(&mut); sleep(3); } printf("thread2: 主函数在等我完成任务吗? \n"); pthread_exit(NULL); } voidthread_create(void) { inttemp; memset(&thread,0,sizeof(thread));//comment1 /*创建线程*/ if((temp=pthread_create(&thread[0],NULL,thread1,NULL))! =0)//comment2 printf("线程1创建失败! \n"); else printf("线程1被创建\n"); if((temp=pthread_create(&thread[1],NULL,thread2,NULL))! =0)//comment3 printf("线程2创建失败"); else printf("线程2被创建\n"); } voidthread_wait(void) { /*等待线程结束*/ if(thread[0]! =0){//comment4 pthread_join(thread[0],NULL); printf("线程1已经结束\n"); } if(thread[1]! =0){//comment5 pthread_join(thread[1],NULL); printf("线程2已经结束\n"); } } intmain() { /*用默认属性初始化互斥锁*/ pthread_mutex_init(&mut,NULL); printf("我是主函数哦,我正在创建线程,呵呵\n"); thread_create(); printf("我是主函数哦,我正在等待线程完成任务阿,呵呵\n"); thread_wait(); return0; } 注意: Gcc–lpthread–othread.outthread.c 线程相关操作 1)pthread_t pthread_t在头文件/usr/include/bits/pthreadtypes.h中定义: typedefunsignedlongintpthread_t; 它是一个线程的标识符。 2)pthread_create 函数pthread_create用来创建一个线程,它的原型为: externintpthread_create__P((pthread_t*__thread,__constpthread_attr_t*__attr, void*(*__start_routine)(void*),void*__arg)); 第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。 这里,我们的函数thread不需要参数,所以最后一个参数设为空指针。 第二个参数我们也设为空指针,这样将生成默认属性的线程。 对线程属性的设定和修改我们将在下一节阐述。 当创建线程成功时,函数返回0,若不为0则说明创建线程失败,常见的错误返回代码为EAGAIN和EINVAL。 前者表示系统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法。 创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。 3)pthread_joinpthread_exit 函数pthread_join用来等待一个线程的结束。 函数原型为: externintpthread_join__P((pthread_t__th,void**__thread_return)); 第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。 这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。 一个线程的结束有两种途径,一种是象我们上面的例子一样,函数结束了,调用它的线程也就结束了;另一种方式是通过函数pthread_exit来实现。 它的函数原型为: externvoidpthread_exit__P((void*__retval))__attribute__((__noreturn__)); 唯一的参数是函数的返回代码,只要pthread_join中的第二个参数thread_return不是NULL,这个值将被传递给thread_return。 最后要说明的是,一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join的线程则返回错误代码ESRCH。 在这一节里,我们编写了一个最简单的线程,并掌握了最常用的三个函数pthread_create,pthread_join和pthread_exit。 下面,我们来了解线程的一些常用属性以及如何设置这些属性。 互斥锁相关 互斥锁用来保证一段时间内只有一个线程在执行一段代码。 1)pthread_mutex_init 函数pthread_mutex_init用来生成一个互斥锁。 NULL参数表明使用默认属性。 如果需要声明特定属性的互斥锁,须调用函数pthread_mutexattr_init。 函数pthread_mutexattr_setpshared和函数pthread_mutexattr_settype用来设置互斥锁属性。 前一个函数设置属性pshared,它有两个取值,PTHREAD_PROCESS_PRIVATE和PTHREAD_PROCESS_SHARED。 前者用来不同进程中的线程同步,后者用于同步本进程的不同线程。 在上面的例子中,我们使用的是默认属性PTHREAD_PROCESS_PRIVATE。 后者用来设置互斥锁类型,可选的类型有PTHREAD_MUTEX_NORMAL、PTHREAD_MUTEX_ERRORCHECK、PTHREAD_MUTEX_RECURSIVE和PTHREAD_MUTEX_DEFAULT。 它们分别定义了不同的上锁、解锁机制,一般情况下,选用最后一个默认属性。 2)pthread_mutex_lockpthread_mutex_unlockpthread_delay_np pthread_mutex_lock声明开始用互斥锁上锁,此后的代码直至调用pthread_mutex_unlock为止,均被上锁,即同一时间只能被一个线程调用执行。 当一个线程执行到pthread_mutex_lock处时,如果该锁此时被另一个线程使用,那此线程被阻塞,即程序将等待到另一个线程释放此互斥锁。 注意: 1)需要说明的是,上面的两处sleep不光是为了演示的需要,也是为了让线程睡眠一段时间,让线程释放互斥锁,等待另一个线程使用此锁。 下面的参考资料1里头说明了该问题。 但是在linux下好像没有pthread_delay_np那个函数(我试了一下,提示没有定义该函数的引用),所以我用了sleep来代替,不过参考资料2中给出另一种方法,好像是通过pthread_cond_timedwait来代替,里头给出了一种实现的办法。 2)请千万要注意里头的注释comment1-5,如果没有comment1和comment4,comment5,将导致在pthread_join的时候出现段错误,另外,上面的comment2和comment3是根源所在,所以千万要记得写全代码。 因为上面的线程可能没有创建成功,导致下面不可能等到那个线程结束,而在用pthread_join的时候出现段错误(访问了未知的内存区)。 另外,在使用memset的时候,需要包含string.h头文件。 实验四 1.实验内容与目的 熟悉有关文件的系统调用,学习文件系统的系统调用命令,提高对文件系统实现功能的理解和掌握。 使用creatopenreadwrite等系统调用用C语言编程实现复制文件。 2.注释 (1)Intcreat(constchar*pathname,mode_tmode); 返回值: 如果正确创建,返回文件的描述符;否则返回-1; Pathname是要创建文件的路径名。 创建文件时,文件只能以只写方式打开 Mode用来规定该文件的拥有者,小组用户和其他用户的访问权限,要求用按位逻辑加对下列符号常量进行所需的组合(同open函数)。 (2)intopen(constchar*pathname,intflags); intopen(constchar*pathname,intflags,mode_tmode); intclose(intfd); open函数有两个形式.其中pathname是我们要打开的文件名(包含路径名称,缺省是认为在当前路径下面).flags可以去下面的一个值或者是几个值的组合. O_RDONLY: 以只读的方式打开文件. O_WRONLY: 以只写的方式打开文件. O_RDWR: 以读写的方式打开文件. O_APPEND: 以追加的方式打开文件. O_CREAT: 创建一个文件. O_EXEC: 如果使用了O_CREAT而且文件已经存在,就会发生一个错误. O_NOBLOCK: 以非阻塞的方式打开一个文件. O_TRUNC: 如果文件已经存在,则删除文件的内容. 前面三个标志只能使用任意的一个.如果使用了O_CREATE标志,那么我们要使用open的第二种形式.还要指定mode标志,用来表示文件的访问权限.mode可以是以下情况的组合. ----------------------------------------------------------------- S_IRUSR用户可以读S_IWUSR用户可以写 S_IXUSR用户可以执行S_IRWXU用户可以读写执行 ----------------------------------------------------------------- S_IRGRP组可以读S_IWGRP组可以写 S_IXGRP组可以执行S_IRWXG组可以读写执行 ----------------------------------------------------------------- S_IROTH其他人可以读S_IWOTH其他人可以写 S_IXOTH其他人可以执行S_IRWXO其他人可以读写执行 ----------------------------------------------------------------- S_ISUID设置用户执行IDS_ISGID设置组的执行ID ----------------------------------------------------------------- 我们也可以用数字来代表各个位的标志.Linux总共用5个数字来表示文件的各种权限. 00000.第一位表示设置用户ID.第二位表示设置组ID,第三位表示用户自己的权限位,第四位表示组的权限,最后一位表示其他人的权限. 每个数字可以取1(执行权限),2(写权限),4(读权限),0(什么也没有)或者是这几个值的和. 比如我们要创建一个用户读写执行,组没有权限,其他人读执行的文件.设置用户ID位那么我们可以使用的模式是--1(设置用户ID)0(组没有设置)7(1+2+4)0(没有权限,使用缺省)5(1+4)即10705: open("temp",O_CREAT,10705); 如果我
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 操作系统 实验 三四