操作系统实验

更新时间:2024-05-17 12:46:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

实验一 Linux 基本命令的使用

一、实验学时:

1学时

二、实验目的:

1. 掌握监视系统的几个Linux基本命令: PS--查看系统的进程 tty--查看当前使用的终端

df--查看系统的文件系统的空间使用情况

du--查看具体某个文件和目录的磁盘空间的占用情况 free--查看使用的内存资源的情况 2. 掌握Linux下的联机帮助手册的使用 3. 掌握Linux命令的简要帮助的获取方法 4. 掌握一些其他常用的Linux命令: adduser--添加新用户 passwd--修改用户口令 ls--查看文件属性 cal--显示日历

date--显示系统的日期和时间 clear--清屏 find--查找文件

uname--查看系统信息

who--查看其他登录的用户 which--查看命令的全路径

tar--Linux下的压缩与解压缩命令

三、实验内容:

1.以root用户身份登陆,并使用“ls”、“cat”、“cd”等命令来实现基本的文件操作并观察Linux文件系统的特点。

2.使用ps查看系统的进程运行情况,使用不同的命令选项并比较显示结果的差别;查看当前系统已安装的文件系统的空间使用情况;查看用户的家目录占用了多少空间;查看使用的内存资源的情况。

3.查看ls命令的详细使用方法,查看ps命令的详细使用方法。 4.获取ls命令的简要帮助信息,获取ps命令的简要帮助信息。

5.用cal命令显示日历,用date命令显示系统的日期和时间,用clear清除屏幕,用find命令在系统中查找文件ch1.doc,用uname命令查看系统的信息,用who命令查看其他登录的用户,用which命令查看一些命令的全路径,用tar命令来压缩test目录下的所有后缀为doc的文件到文件doc.tar.gz中,将doc.tar.gz复制到用户的家目录并展开压缩文件。

实验二 进程的创建

一、实验学时:

1学时

二、实验目的:

1、 加深对进程概念的理解,明确进程和程序的区别 2、 进一步认识并发执行的实质

三、实验内容:

1、阅读linux的fork.c源码文件,分析进程的创建过程 2、学会在linux环境下编程及使用gcc编译器 3、编写一个输出“Hello world”的程序

4、编写一段程序,使用系统调用fork()函数创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符;父进程显示字符“a”,子进程分别显示字符“b”和“ c”。

【程序】 #include main() {

int p1,p2;

while((p1=fork())= =-1); /*创建子进程p1,失败时循环*/ if(p1= =0) /*子进程p1创建成功*/ putchar(?b?);

else /*父进程返回*/ {

while((p2=fork())= =-1); /*创建另一个子进程p2,失败时循环*/ if(p2= =0) /*子进程p2创建成功*/ putchar(?c?); else

putchar(?a?); /*父进程执行*/ } }

5、修改已编写的程序,将每个进程的输出由单个字符改为一句话,再观察程序执行时屏幕上出现的现象,并分析其原因。

【程序1】 #include main() {

int p1,p2,i;

while((p1=fork())= =-1); if(p1= =0)

for(i=0;i<50;i++) printf(“child %d\\n”,i); else

{

while((p2=fork())= =-1) if(p2= =0)

for(i=0;i<50;i++) printf(“son %d\\n”,i); else

for(i=0;i<50;i++)

printf(“daughter %d\\n”,i); } }

实验三 进程的管理

一、实验学时:

2学时

二、实验目的:

分析进程争用资源的现象,学习解决进程互斥的方法

三、实验内容:

1、阅读linux的sched.h源码文件,加深对进程管理概念的理解

2、在以下程序中使用系统调用lockf()来给进程加锁,实现进程之间的互斥,观察并分析出现的现象

#include main() {

int p1,p2,i;

while((p1==fork())==-1); if(p1==0)

for(i=0;i<500;i++) printf(\else

{while((p2==fork())==-1); if(p2==0)

for(i=0;i<500;i++) printf(\else

for(i=0;i<500;i++)

printf(\} }

〈程序1〉

#include main() {

int p1,p2,i; if(p1=fork()) { for(i=0;i<500;i++) printf(\

wait(0); /* 保证在子进程终止前,父进程不会终止*/ exit(0); } else { if(p2=fork()) { for(i=0;i<500;i++) printf(\

wait(0); /* 保证在子进程终止前,父进程不会终止*/ exit(0); /*向父进程信号0且该进程推出*/

}

else { for(i=0;i<500;i++)

}

printf(“grandchild %d\\n\ exit(0);

} }

〈运行结果〉

parent?. son?

grandchild? grandchild? 或grandchild ?son

?grandchild ?son ?parent

分析:由于函数printf()输出的字符串之间不会被中断,因此,每个字符串内部的字符顺序输出时不变。但是 , 由于进程并发执行时的调度顺序和父子进程的抢占处理机问题,输出字符串的顺序和先后随着执行的不同而发生变化。这与打印单字符的结果相同。

实验四 进程软中断通信

一、实验学时:

2学时

二、实验目的:

了解linux系统中进程软中断通信的基本原理

了解signal(SIGINT,SIG_IGN)和signal(SIGQUIT,SIG_IGN)两条语句的功能

三、实验内容:

1.在程序中使用系统调用fork()来创建进程,再用系统调用signal()让父进程捕捉键盘上来的中断信号(即按del键),当捕捉到中断信号后,父进程用系统调用kill()向两个子进程发出信号,观察并分析出现的现象

#include #include

void waiting(),stop(); int wait_mark:

main(){

int p1,p2;

while((p1==fork())==-1); if(p1>0){

while((p2==fork())==-1); if(p2>0){wait_mark=1; signal(SIGNAL,stop); waitting(0); kill(p1,16); kill(p2,17); wait(0); wait(0);

printf(\exit(0); } else

{wait_mark=1; signal(17,stop); waitting(); lockf(stdout,1,0);

printf(\lockf(stdout,0,0); exit(0);} } else

{wait_mark=1; signal(16,stop); waitting();

lockf(stdout,1,0);

printf(\ lockf(stdout,0,0); exit(0); } }

void waitting()

{while(wait_mark!=0); }

void stop() {wait_mark=0; }

〈程序〉

#include

#include #include

void waiting(),stop(),alarming(); int wait_mark;

main() { int p1,p2; if(p1=fork()) /*创建子进程p1*/ { if(p2=fork()) /*创建子进程p2*/ { wait_mark=1; signal(SIGINT,stop); /*接收到^c信号,转stop*/ signal(SIGALRM,alarming);/*接受SIGALRM waiting(); kill(p1,16); /*向p1发软中断信号16*/ kill(p2,17); /*向p2发软中断信号17*/ wait(0); /*同步*/ wait(0); printf(\ exit(0); } else { wait_mark=1; signal(17,stop); signal(SIGINT,SIG_IGN); /*忽略 ^c信号*/ while (wait_mark!=0); lockf(1,1,0); printf(\ is killed by parent!\\n\ lockf(1,0,0); exit(0); } } else { wait_mark=1; signal(16,stop);

signal(SIGINT,SIG_IGN); /*忽略^c信号*/

while (wait_mark!=0)

lockf(1,1,0); printf(\ lockf(1,0,0); exit(0); } }

void waiting() { sleep(5);

if (wait_mark!=0)

kill(getpid(),SIGALRM); }

void alarming() { wait_mark=0; }

void stop() { wait_mark=0; }

<运行结果>

不做任何操作等待五秒钟父进程回在子进程县推出后退出,并打印退出的顺序;或者点击ctrl+C后程序退出并打印退出的顺序。

2.在程序中使用signal(SIGINT,SIG_IGN)和signal(SIGQUIT,SIG_IGN),观察执行的结果并分析出现的现象

#include #include Int pid1,pid2;

Int EndFlag=0; Pf1=0; Pf2=0;

Void IntDelete() { kill (pid1,16); kill (pid2,17); EndFlag=1;

}

void Int1() { printf(“child process 1 is killed ! by parent \\n”); exit(0); }

void Int2() { Printf(“child process 2 is killed ! by parent\\n”); Exit(0); }

Main() { Int exitpid; Signal(SIGINT,SIG_IGN); Singal(SIGQUIT,SIG_IGN); While ((pid1==fork())==-1); If (pid==0) {

Signal(SIGUSR1,Int1); Singal(SIGINT,SIG_IGN); Pause(); Exit(0); } Else { While ((pid==fork())==-1); If (pid2==0) { Signal(SIGUSR1,Int1); Signal(SIGINT,SIG_IGN); Pause(); Exit(0);

} Else { Signal(SIGINT,IntDelete); Waitpid(-1,&exitcode,0); Printf(“parent process is killed\\n”); exit(0); } }

<程序>

#include #include #include int pid1,pid2; int EndFlag=0; int pf1=0; int pf2=0;

void IntDelete() { kill(pid1,16); kill(pid2,17); }

void Int1() { printf(\ exit(0); }

void Int2() { printf(\ exit(0); }

main() { int exitpid; if(pid1=fork()) { if(pid2=fork()) { signal(SIGINT,IntDelete); waitpid(-1,&exitpid,0); waitpid(-1,&exitpid,0); printf(\ exit(0); } else { signal(SIGINT,SIG_IGN);

} }

signal(17,Int2); pause(); } } else { signal(SIGINT,SIG_IGN); signal(16,Int1); pause(); }

实验五 进程管道通信

一、实验学时:

2学时

二、实验目的:

了解linux系统中进程管道通信的基本原理 了解pipe( )函数的功能

三、实验内容:

编制一段程序,实现进程的管道通信。

使用系统调用pipe()建立一条管道线;两个子进程P1和P2分别向管道中写一句话: Child 1 is sending a message! Child 2 is sending a message!

而父进程则从管道中读出来自于两个子进程的信息,显示在屏幕上。

要求父进程先接收子进程P1发来的消息,然后再接收子进程P2发来的消息。

〈程序〉

#include #include #include int pid1,pid2;

main( ) {

int fd[2];

char outpipe[100],inpipe[100];

pipe(fd); /*创建一个管道*/ while ((pid1=fork( ))==-1); if(pid1==0) {

lockf(fd[1],1,0);

sprintf(outpipe,\ /*把串放入数组outpipe中*/

write(fd[1],outpipe,50); /*向管道写长为50字节的串*/ sleep(5); /*自我阻塞5秒*/ lockf(fd[1],0,0); exit(0); } else {

while((pid2=fork( ))==-1); if(pid2==0)

{

lockf(fd[1],1,0); /*互斥*/

sprintf(outpipe,\ write(fd[1],outpipe,50); sleep(5);

lockf(fd[1],0,0); exit(0); } else {

wait(0); /*同步*/

read(fd[0],inpipe,50); /*从管道中读长为50字节的串*/ printf(\ wait(0);

read(fd[0],inpipe,50); printf(\ exit(0); } } }

实验六 进程间通信(1)

一、实验学时:

2学时

二、实验目的:

了解Linux支持的消息通讯机制及信息量机制

三、实验内容:

消息的创建,发送和接收。

① 使用系统调用msgget ( ), msgsnd ( ), msgrev ( ), 及msgctl ( ) 编制一长度为1k的消息的发送和接收程序。

②观察分析程序,说明控制消息队列系统调用msgctl ( ) 在此起什么作用?

〈任务〉

使用系统调用msgget( ), megsnd( ), msgrev( )及msgctl()编制一长度为1K的消息发送和接收的程序 。 〈程序〉

#include #include #include #include

#define MSGKEY 75 /*定义关键词MEGKEY*/ struct msgform /*消息结构*/ { long mtype; char mtexe[100]; /*文本长度*/ }msg;

int msgqid,i;

void CLIENT( ) { int i; msgqid=msgget(MSGKEY,0777|IPC_CREAT); for(i=10;i>=1;i--) { msg.mtype=i; printf(\ msgsnd(msgqid,&msg,1030,0); /*发送消息msg入msgid消息队列*/ } exit(0); }

void SERVER( ) {

msgqid=msgget(MSGKEY,0777|IPC_CREAT); /*由关键字获得消息队列*/ do { msgrcv(msgqid,&msg,1030,0,0); /*从队列msgid接受消息msg*/ printf(\

}while(msg.mtype!=1); /*消息类型为1时,释放队列*/ msgctl(msgqid, IPC_RMID,0); }

main() {

if(fork()) {

SERVER(); wait(0);

} else CLIENT( ); }

<结果>

从理想的结果来说,应当是每当Client发送一个消息后,server接收该消息,Client再发送下一条。也就是说“(Client)sent”和“(server)received”的字样应该在屏幕上交替出现。实际的结果大多是,先由 Client 发送两条消息,然后Server接收一条消息。此后Client

Server交替发送和接收消息.最后一次接收两条消息. Client 和Server 分别发送和接收了10条消息,与预期设想一致 <分析>

message的传送和控制并不保证完全同步,当一个程序不再激活状态的时候,它完全可能继续睡眠,造成上面现象,在多次send message 后才 receive message.这一点有助于理解消息转送的实现机理.

2.共享存储区的创建,附接和断接

实验七 进程间通信(2)

一、实验学时:

2学时

二、实验目的:

了解Linux支持的共享存储区机制及信息量机制。

三、实验内容:

共享存储区的创建、附接和段接。

使用系统调用shmget( ),shmat( ),sgmdt( ),shmctl( ),编制一个与上述功能相同的程序。

<程序>

#include #include #include

#define SHMKEY 75 /*定义共享区关键词*/ int shmid,i; int *addr;

CLIENT() { int i; shmid=shmget(SHMKEY,1024, 0777|IPC_CREAT); /*获取共享区,长度1024,关键词SHMKEY*/ addr=shmat(shmid,0,0); /*共享区起始地址为addr*/ for(i=9;i>=0;i--) { while(*addr!= -1); printf(\ /*打印(client)sent*/ *addr=i; /*把i赋给addr*/ } exit(0); }

SERVER() { do { while(*addr = =-1); printf(\ /*服务进程使用共享区*/

if(*addr!=0) *addr=-1;

} while(*addr); wait(0); shmctl(shmid,IPC_RMID,0); }

main() { shmid=shmget(SHMKEY,1024,0777|IPC_CREAT); /*创建共享区*/ addr=shmat(shmid,0,0); /*共享区起始地址为addr*/

}

<结果〉

运行的结果和预想的完全一样。但在运行的过程中,发现每当client发送一次数据后,server要等大约0.1秒才有响应。同样,之后client又需要等待大约0.1秒才发送下一个数据。 <分析〉

出现上述的应答延迟的现象是程序设计的问题。当client端发送了数据后,并没有任何措施通知server端数据已经发出,需要由client的查询才能感知。此时,client端并没有放弃系统的控制权,仍然占用CPU的时间片。只有当系统进行调度时,切换到了server进程,再进行应答。这个问题,也同样存在于server端到client的应答过程之中。

*addr=-1; if(fork()) {

SERVER(); } else {

CLIENT(); }

实验八 存储管理

一、实验学时:

4学时

二、实验目的:

存储管理的主要功能之一是合理地分配空间。请求页式管理是一种常用的虚拟存储管理技术。

本实验的目的是通过请求页式存储管理中页面置换算法模拟设计,了解虚拟存储技术的技术特点,掌握请求页式存储管理的页面置换算法。 三、实验内容:

(1)通过随机数产生一个指令序列,共320条指令。指令的地址按下述原则生成: ①50%的指令是顺序执行的;

②50%的指令是均匀分布在前地址部分; ③50%的指令是均匀分布在后地址部分。 具体的实施方法是:

①在 [0,319] 的指令之间随即选取一起点m;

②顺序执行一条指令,即执行地址为m+1的指令;

③在前地址[0,m+1]中随机选取一条指令并执行,该指令的地址为m′; ④顺序执行一条指令,其地址为 m′+ 1;

⑤在后地址[m′+ 2,319]中随机选取一条指令并执行; ⑥重复上述步骤①-⑤,直到执行320次指令。

(2)将指令序列变换为页地址流 设:①页面大小为1k;

②用户内存容量为4页到32页; ③用户虚存容量为32k。 在用户虚存中,按每k存放10条指令排在虚存地址,即320条指令在虚存中的存放方式为:

第0条-第9条指令为第0页(对应虚存地址为[0,9]); 第10条-第19条指令为第一页(对应虚存地址为[10,19]); … …

第310条~第319条指令为第31页(对应虚地址为[310,319])。 按以上方式,用户指令可组成32页。

(3)计算并输出下述各种算法在不同内存容量下的命中率。 ①先进先出的算法(FIFO); ②最近最少使用算法(LRR);

③最佳淘汰算法(OPT)先淘汰最不常用的页地址; ④最少访问页面算法(LFR); ⑤最近最不经常使用算法(NUR)。 其中③、④、⑤为选择内容。

命中率=1-页面失效次数/页地址流长度

在本实验中,页地址流长度为320,页面失效次数为每次访问相应指令时,该指令所对应的页不在内存的次数。

3、随机数产生办法,Linux或UNIX系统提供函数strand()和rand(),分别进行初始化和产生随机数。例如: strand ();

语句可初始化一个随机数; a[0]=10*rand()/65535*319+1; a[1]=10*rand()/65535*a[0];

语句可用来产生a[0]与a[1]中的随机数。

本文来源:https://www.bwwdw.com/article/52q7.html

Top