《2022年操作系统实验 8》由会员分享,可在线阅读,更多相关《2022年操作系统实验 8(12页珍藏版)》请在金锄头文库上搜索。
1、实验二进入 VI 编辑器格式: vi 文件名例 :vi sy.c Vi 编辑器三种工作方式:1编辑方式:进入VI 处于编辑方式2文本输入方式:在编辑方式下输入a ,进入追加方式,输入i,进入插入方式3 命令方式:在输入方式下,按Esc 键,由文本输入转向编辑方式,输入冒号:进入命令方式4退出 vi : wq 写文件退出:w wenjianming 写文件: q! 不写退出:wq! 写退出编译 c 文件Gcc -o wenjianming.out wenjianming.c 运行文件:./wenjianming.out 1 实验内容和目的用 vi 编辑器编辑下列文件,使用gcc 编译器和gdb
2、调试器,对下列程序编译运行,分析运行结果。要求至少完成3 个程序。2程序示例(1) /* 父子进程之间的同步之例*/ #include main( ) int pid1; if(pid1=fork() /*create child1 */ if (fork() /*create the child2*/ printf (“ parent n” );printf(“ parent is waiting the child1 terminate.n); wait(0); printf(“ parent is waiting the child2 terminate.n” );wait(0); pr
3、intf(“ parent terminate.n” );exit(0); else /* child2*/ printf(“ child2 s context.n” );名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 12 页 - - - - - - - - - sleep(5); printf(“ child2 terminate.n” );exit(0); else if(pid1=0)/* child1 */ printf(“ child1 s context.n
4、” );sleep(10); printf(“ child1 terminate.n” );exit(0); 分析:上述程序是父进程首先创建一个子进程,若成功,再创建另一个子进程,之后三个进程并发执行。 究竟谁先执行,是随机的,可根据执行结果判断。试分析该程序的所有运行结果。注释:fork( ) 调用正确完成时,给父进程返回地是被创建子进程的标识,给子进程返回的是 0;创建失败时,返回给父进程的时1;exit(0) 进程终止自己wait(0) 父进程同步等待子进程结束,即无子进程结束,父进程等待。(2)管道通信机制通过使用管道实现两个和多个进程之间的通信。所谓管道,就是将一个进程的标准输出与另
5、一个进程的标准输入联系在一起,进行通信的一种方法。同组进程之间可用无名管道进行通信,不同组进程可通过有名管道通信。使用无名管道进行父子进程之间的通信 include #include #include int pipe( int filedes2); char parent=” a message to pipe communication.n” ;main() int pid,chan12; char buf100; pipe(chan1); pid=fork(); if(pid0) close(chan10); /* 父进程关闭读通道*/ printf(“ parent process s
6、ends a message to child.n” );write(chan11,parent,sizeof(parent); close(chan11); printf(“ parent process waits the child to terminate.n” );名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 12 页 - - - - - - - - - wait(0); printf(“ parent process terminates.n” ); els
7、e close(chan11);/* 子进程关闭写通道*/ read(chan10,buf,100); printf(“ the message read by child process form parent is %s.n” ,buf);close (chan10); printf(“ child process terminatesn” ); 观察运行结果。注释 :pipe( int filedes2) :创建一个无名管道,filedes0 为读通道, filedes1 为写通道。(3)Linux 中的多线程编程threads.c #include #include #include
8、#include #define MAX 10 pthread_t thread2; pthread_mutex_t mut; int number=0, i; void *thread1() printf (thread1 : Im thread 1n); for (i = 0; i MAX; i+) printf(thread1 : number = %dn,number); pthread_mutex_lock(&mut); number+; pthread_mutex_unlock(&mut); sleep(2); printf(thread1 :主函数在等我完成任务吗?n); pth
9、read_exit(NULL); void *thread2() printf(thread2 : Im thread 2n); for (i = 0; i MAX; i+) 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 12 页 - - - - - - - - - printf(thread2 : number = %dn,number); pthread_mutex_lock(&mut); number+; pthread_mutex_unlock(&mut); s
10、leep(3); printf(thread2 :主函数在等我完成任务吗?n); pthread_exit(NULL); void thread_create(void) int temp; memset(&thread, 0, sizeof(thread); /comment1 /*创建线程 */ if(temp = pthread_create(&thread0, NULL, thread1, NULL) != 0) /comment2 printf(线程 1 创建失败 !n); else printf(线程 1 被创建 n); if(temp = pthread_create(&thre
11、ad1, NULL, thread2, NULL) != 0) /comment3 printf(线程 2 创建失败 ); else printf(线程 2 被创建 n); void thread_wait(void) /*等待线程结束*/ if(thread0 !=0) /comment4 pthread_join(thread0,NULL); printf(线程 1 已经结束 n); if(thread1 !=0) /comment5 pthread_join(thread1,NULL); printf(线程 2 已经结束 n); int main() 名师资料总结 - - -精品资料欢迎
12、下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,共 12 页 - - - - - - - - - /*用默认属性初始化互斥锁*/ pthread_mutex_init(&mut,NULL); printf(我是主函数哦,我正在创建线程,呵呵n); thread_create(); printf(我是主函数哦,我正在等待线程完成任务阿,呵呵n); thread_wait(); return 0; 3 注意: Gcc lpthread o thread.out thread.c线程相关操作1) pthread_t
13、pthread_t 在头文件 /usr/include/bits/pthreadtypes.h 中定义:typedef unsigned long int pthread_t; 它是一个线程的标识符。2)pthread_create 函数 pthread_create 用来创建一个线程,它的原型为:extern int pthread_create _P (pthread_t *_thread, _const pthread_attr_t *_attr, void *(*_start_routine) (void *), void *_arg); 第一个参数为指向线程标识符的指针,第二个参数用
14、来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。这里,我们的函数thread不需要参数,所以最后一个参数设为空指针。第二个参数我们也设为空指针,这样将生成默认属性的线程。 对线程属性的设定和修改我们将在下一节阐述。当创建线程成功时,函数返回 0, 若不为 0则说明创建线程失败, 常见的错误返回代码为EAGAIN 和 EINVAL 。前者表示系统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法。创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。3)pthread_join pthread_ex
15、it 函数 pthread_join 用来等待一个线程的结束。函数原型为:extern int pthread_join _P (pthread_t _th, void *_thread_return); 第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。一个线程的结束有两种途径,一种是象我们上面的例子一样,函数结束了,调用它的线程也就结束了;另一种方式是通过函数pthread_exit 来实现。它的函数原型为:extern void
16、 pthread_exit _P (void *_retval) _attribute_ (_noreturn_); 唯一的参数是函数的返回代码,只要pthread_join中的第二个参数thread_return 不是NULL ,这个值将被传递给thread_return。最后要说明的是,一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join 的线程则返回错误代码 ESRCH。在这一节里, 我们编写了一个最简单的线程,并掌握了最常用的三个函数pthread_create,名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - -
17、 - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 12 页 - - - - - - - - - pthread_join 和 pthread_exit。下面,我们来了解线程的一些常用属性以及如何设置这些属性。互斥锁相关互斥锁用来保证一段时间内只有一个线程在执行一段代码。1) pthread_mutex_init 函数 pthread_mutex_init 用来生成一个互斥锁。NULL 参数表明使用默认属性。如果需 要 声 明 特 定 属 性 的 互 斥 锁 , 须 调 用 函 数pthread_mutexattr_init 。 函 数pthread_m
18、utexattr_setpshared 和函数pthread_mutexattr_settype 用来设置互斥锁属性。前一个函数设置属性pshared,它有两个取值,PTHREAD_PROCESS_PRIVATE和PTHREAD_PROCESS_SHARED 。前者用来不同进程中的线程同步,后者用于同步本进程的不同线程。在上面的例子中,我们使用的是默认属性PTHREAD_PROCESS_ PRIVATE 。后者用来设置互斥锁类型,可选的类型有PTHREAD_MUTEX_NORMAL、PTHREAD_MUTEX_ERRORCHECK、 PTHREAD_MUTEX_RECURSIVE和 PTHRE
19、AD _MUTEX_DEFAULT。它们分别定义了不同的上锁、解锁机制,一般情况下,选用最后一个默认属性。2) pthread_mutex_lock pthread_mutex_unlock pthread_delay_np pthread_mutex_lock 声明开始用互斥锁上锁,此后的代码直至调用pthread_mutex_unlock为 止 , 均 被 上 锁 , 即 同 一 时 间 只 能 被 一 个 线 程 调 用 执 行 。 当 一 个 线 程 执 行 到pthread_mutex_lock 处时,如果该锁此时被另一个线程使用,那此线程被阻塞,即程序将等待到另一个线程释放此互斥锁
20、。注意:1)需要说明的是,上面的两处sleep不光是为了演示的需要,也是为了让线程睡眠一段时间,让线程释放互斥锁,等待另一个线程使用此锁。2)请千万要注意里头的注释comment1-5,如果没有comment1 和 comment4,comment5,将导致在pthread_join 的时候出现段错误,另外,上面的comment2 和 comment3 是根源所在,所以千万要记得写全代码。因为上面的线程可能没有创建成功,导致下面不可能等到那个线程结束,而在用pthread_join 的时候出现段错误(访问了未知的内存区)。另外,在使用memset 的时候,需要包含string.h 头文件。实验
21、报告(1)实验题目。(2)说明对程序的理解,程序后加上注释语句。(3)分析程序的执行结果并加以解释。实验三1实验内容与目的熟悉有关文件的系统调用,学习文件系统的系统调用命令,提高对文件系统实现功能的理解和掌握。使用creat open read write 等系统调用用C 语言编程实现复制文件。2注释(1) Int creat(const char *pathname, mode_t mode); 返回值:如果正确创建,返回文件的描述符;否则返回1;Pathname是要创建文件的路径名。创建文件时,文件只能以只写方式打开Mode 用来规定该文件的拥有者,小组用户和其他用户的访问权限,要求用按位
22、逻辑加对下名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 6 页,共 12 页 - - - - - - - - - 列符号常量进行所需的组合(同open 函数)。(2) int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode); int close(int fd); open 函数有两个形式.其中 pathname 是我们要打开的文件名(包含路径名
23、称,缺省是认为在当前路径下面 ).flags 可以去下面的一个值或者是几个值的组合. O_RDONL Y:以只读的方式打开文件. O_WRONL Y:以只写的方式打开文件. O_RDWR: 以读写的方式打开文件. O_APPEND: 以追加的方式打开文件. O_CREAT:创建一个文件 . O_EXEC: 如果使用了O_CREAT 而且文件已经存在,就会发生一个错误. O_NOBLOCK: 以非阻塞的方式打开一个文件. O_TRUNC: 如果文件已经存在,则删除文件的内容. 前面三个标志只能使用任意的一个.如果使用了O_CREATE 标志 ,那么我们要使用open 的第二种形式 .还要指定mo
24、de 标志 ,用来表示文件的访问权限.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 设置用户执行ID S_ISGID 设置组的执行ID - 我们也可以用数字来代表各个位的标志.Linux 总共用 5 个数字来表示文件的各种权限. 00000.第
25、一位表示设置用户ID. 第二位表示设置组ID,第三位表示用户自己的权限位,第四位表示组的权限 ,最后一位表示其他人的权限. 每个数字可以取1(执行权限 ),2(写权限 ),4(读权限 ),0(什么也没有 )或者是这几个值的和. 比如我们要创建一个用户读写执行,组没有权限 ,其他人读执行的文件.设置用户ID 位那么我们可以使用的模式是-1(设置用户ID)0( 组没有设置 )7(1+2+4)0( 没有权限 ,使用缺省 )5(1+4) 即10705: open(temp,O_CREA T,10705); 如果我们打开文件成功,open 会返回一个文件描述符.我们以后对文件的所有操作就可以对这个文件描
26、述符进行操作了. 当我们操作完成以后,我们要关闭文件了,只要调用close 就可以了 ,其中 fd 是我们要关闭的文件描述符 . (3)ssize_t read(int fd, void *buffer, size_t count); ssize_t write(int fd, const void *buffer, size_t count); fd 是我们要进行读写操作的文件描述符,buffer 是我们要写入文件内容或读出文件内容的内存地址 .count 是我们要读写的字节数. 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - -
27、 名师精心整理 - - - - - - - 第 7 页,共 12 页 - - - - - - - - - 对于普通的文件read从指定的文件 (fd) 中读取 count 字节到 buffer 缓冲区中 (记住我们必须提供一个足够大的缓冲区),同时返回count. 如果 read 读到了文件的结尾或者被一个信号所中断,返回值会小于count.如果是由信号中断引起返回 ,而且没有返回数据,read会返回 -1,且设置 errno 为 EINTR. 当程序读到了文件结尾的时候 ,read会返回 0. write 从 buffer 中写 count 字节到文件fd 中 ,成功时返回实际所写的字节数.
28、 可能用到的头文件#include #include #include #include #include 4 实验报告(1)实验题目。(2)采用的数据结构及符号说明。(3)打印一份源程序清单,并附加流程图与注释。(4)分析文件系统中常用的系统调用。实验四模拟内存管理程序( 4 学时)1、 实验目的了解简单的固定大小内存分配方法,掌握分区存储管理技术,了解在分区管理机制下所需的数据结构。2、 实验内容1)、将 1024K 内存按如下块大小分成十个内存块。内存块号内存块大小起始地址内存块状态1 512 10 NO 2 256 522 NO 3 256 778 NO 4 128 1034 NO 5
29、 128 1162 NO 6 128 1290 NO 7 32 1418 NO 8 32 1450 NO 9 16 1482 NO 10 16 1498 NO 其中,在内存状态中用NO 代表该内存块未被分配; 用进程名代表该内存块已被分配。2)、编制模拟内存管理程序,根据调入内存的进程大小分别采用最先适应法和最佳适应法分配内存块。最佳适应法,如有一个12K 的程序被运行时,它应该被分配到内存块号9,若有 200K 的程序运行时,应将其调入内存块号2。最先适应法, 则是按内存块号的顺序, 依次放入各进程名。 有关编程请仔细阅读后名师资料总结 - - -精品资料欢迎下载 - - - - - - -
30、 - - - - - - - - - - - 名师精心整理 - - - - - - - 第 8 页,共 12 页 - - - - - - - - - 面的参考流程。3、 实验要求1)、要求通过键盘输入若干进程名称和程序所占内存空间的大小,把这些进程分配到内存表中,显示内存分配情况。2)、编制程序可以循环输入,输入某进程结束或某进程添加进来、进程占用存储空间的大小,并显示内存分配情况。3)、当没有区间存放程序时,应有提示。4)、所编写的程序,应有退出功能。5)、每添加、结束一个进程,应有输出显示,输出显示的格式如下:内存块号内存块大小起始地址进程名(内存状态)1 512 10 A1 2 256
31、522 NO 3 256 778 A2 4 128 1034 A3 5 128 1162 NO 6 128 1290 NO 7 32 1418 NO 8 32 1450 NO 9 16 1482 NO 10 16 1498 NO 4、实验报告格式要求1)、实验题目2)、程序所采用的数据结构、符号说明,及采用哪一种内存分配方法3)、写出源程序清单,要求附加流程图与注释4)、写出内存分配的变化情况实验五进程管理设计一.目的和要求进程调度是处理机管理的核心内容。本实验要求用C 语言编写和调试一个简单的进程调度程序。 通过本实验可以加深理解有关进程控制块、进程队列的概念,并体会和了解优先数和时间片轮转
32、调度算法的具体实施办法。二.实验内容1.设计进程控制块PCB 表结构,分别适用于优先数调度算法和循环轮转算法。PCB 结构通常包括以下信息:进程名、进程优先数(或轮转时间片)、进程所占用的 CPU 时间、进程的状态、当前队列指针等。根据调度算法的不同,PCB 结构的内容可以做适当的删除。2.建立进程就绪队列,对两种不同算法编制入链子程序。3.编制两种进程调度算法:1)优先数调度;2)循环轮转调度。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 9 页,共 12 页 - - - - -
33、 - - - - 三.实验环境1.IBM 286 以上微型计算机及其兼容机。2.DOS 系统要求3.3 及更高的版本。3.TURBO C 2.0 。四.实验要求本实验要求用C 语言编写, 选用优先数算法和简单时间片轮转法对五个进程进行调度,每个进程可以有三种状态:运行状态 ( RUN) 、就绪状态 (READY )和完成状态 (FINISH ) 。并假定初始状态为就绪状态。五.模拟算法提示1数据结构设计进程控制块结构如下:PCB:NAME PRIO/ROUND CPUTIME COUNT NEEDTIME STATE NEXT 其中:NAME 进程标识符PRIO进程优先数ROUND 进程轮转时
34、间片CPUTIME 进程占用CPU 时间COUNT 计数器NEEDTIME 进程完成还要的CPU 时间STATE进程的状态NEXT 链指针进程控制块链结构中主要指针如下:RUN当前运行进程指针READY 就绪队列头指针TAIL 就绪队列尾指针FINISH 完成队列头指针为了方便处理, 程序中进程的运行时间以时间片为单位计算。各进程的优先数或轮转时间片数以及进程需运行的时间片数的初值均由用户给定。2程序说明1)在优先数算法中,进程每执行一次,优先数减3,CPU 时间片数加1,进程还需要的时间片数减1。在轮转法中,采用固定时间片,时间片数为2,进程每次执行一次,CPU时间片加2,进程还需要的时间片
35、数减2,并排列就绪队列的尾上。2) 程序结构说明如下:整个程序由FIRSTIN ,INSERT1,INSERT2 ,PRINT ,CREAT,PRISCH 和 ROUNDSCH名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 10 页,共 12 页 - - - - - - - - - 函数组成。其中:INSERT1 的功能是把还未完成且优先数小于别的进程的进程PCB 按进程优先数的顺序插入到就绪队列中。INSERT2 是轮转法使用的函数,将执行了一个单位时间片数(为 2)且还未完成的进
36、程的 PCB 插到就绪队列的队尾。FIRSTIN 的功能是将就绪队列中的第一个进程投入运行。PRINT 打印每执行一个时间片后的所有进程的状态,这里,就绪(等待)用“W”代表。CREATE 的功能是创建新的进程,即创立进程的PCB,并将此 PCB 链入到就绪队列中去。PRISCH 按优先数算法调度进程。ROUNDSCH 按时间片轮转法调度进程。主程序中定义了PCB 的结构和其它变量:number进程数, algo 为 10 个字符长的字符串, 存放要求输入的算法的名,PRIORITY 为优先数算法, ROUNDROBIN为循环轮转法,在程序运行时输入其中的一个。3主要算法算法PRISCH wh
37、ile ( 当前运行进程不为空) 进程占用 CPU 时间加 1 进程到完成还要的CPU 时间减 1 进程优先数减3 if(进程到完成还要的CPU 时间为 0) 将该进程插入到完成队列中修改该进程状态当前运行进程指针为空if(就绪队列不为空)FIRSTIN 函数 else if ( 就 绪 队 列 不 为 空 且 当 前 进 程 优 先 数 小 于 就 绪 队 列 中 第 一个进程的优先数) 修改当前进程状态为W INSERT1 函数FIRSTIN 函数 PRINT 函数 算法ROUNDSCH while (当前运行进程不为空) 进程占用 CPU 时间加 1 进程到完成还要的CPU 时间减 1
38、进程计数器加1 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 11 页,共 12 页 - - - - - - - - - if(进程到完成还要的CPU 时间为 0) 将该进程插入到完成队列中修改该进程状态当前运行进程指针为空if(就绪队列不为空)FIRSTIN 过程 else if (进程计数器等于进程轮转时间片) 修改当前进程计数器为0 if(就绪队列不为空) 修改当前进程状态为W INSERT2 过程FIRSTIN 过程 PRINT 过程 六.实验报告1 实验题目。2 采用的数据结构及符号说明。3 打印一份源程序清单,并附加流程图与注释。4 打印出两种算法的执行结果。5 比较两种算法的优缺点并分析实验过程中遇到的问题,谈谈实验后的体会。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 12 页,共 12 页 - - - - - - - - -