操作系统实验指导书(完整版)
操作系统实验指导书
烟台大学计算机学院
操作系统课程组
2008-9-20
第一部分 操作系统上机指导
Linux操作系统环境:
RedHat Enterprise Linux ES release 3 (Taroon Update 1) (2.4.21-9.EL)
Red Flag Linux release 4.0 (HOT) (2.4)
登录到系统
常用命令练习:
用root账号(超级用户)注册,口令为computer(注意大小写)。注册成功出现#号(超级用户系统提示符,普通用户的系统提示符为$)。
1. 注销(退出)系统:logout 或exit
3.练习使用命令ls(注意Linux命令区分大小写。)
使用ls 查看当前目录内容;使用ls 查看指定目录内容,如/目录,/etc目录
使用ls –all 查看当前目录内容;使用dir 查看当前目录内容
4.使用cd改变当前目录
cd .. 回到上层目录 ;cd / 回到根目录
5.pwd 显示当前路径
6.建立目录mkdir
mkdir 目录名 ; mkdir /home/s2001/newdir
7.删除目录:rmdir;
8.复制文件cp: 如 cp 文件名1 文件名2
9.移动文件或目录: mv
10.删除文件 rm
11. 显示文件内容:more (分页显示);
12. 显示文件:cat 文件名 建立文件:cat >文件名,ctrl+d结束输入
使用编辑器vi 编辑文件
1. 进入linux的文本模式之后,在命令行键入vi filename.c 然后回车。下面作一些简单的解释:首先vi命令是打开vi编辑器。后面的filename.c是用户即将编辑的c文件名字,注意扩展名字是.c;当然,vi编辑器功能很强,可以用它来编辑其它格式的文件,比如汇编文件,其扩展名字是.s;也可以直接用vi打开一个新的未命名的文件,当保存的时候再给它命名,只是这样做不很方便。
2. 最基本的命令I :当进入刚打开的文件时,不能写入信息,这时按一下键盘上的I键(insert),插入的意思,就可以进入编辑模式了。如下图所示:
3. a与i是相同的用法
4. 当文件编辑完后,需要保存退出,这时需要经过以下几个步骤:1)按一下键盘上的Esc 键;2)键入冒号(:),紧跟在冒号后面是wq(意思是保存并退出)。如果不想保存退出,则在第二步键入冒号之后,键入q!(不带w,机尾部保存)。如下图所示:
5. 退出vi编辑器的编辑模式之后,要对刚才编写的程序进行编译。编译的命令是:gcc filename.c [-o outputfilename.out],其中gcc是c的编译器。参数:filename.c 是要编译的源文件的名称,outputfilename表示输出文件名称,中括号表示括号内部的内容可输入也可以不输入(中括号本身不再命令行中出现)。如果不输入outputfilename.out,默认的输出文件是a.out 。
6. 最后一步是运行程序,方法如下:./outputfilename.out
添加新用户、修改文件属性
1. 添加新用户(在root下,按默认值回答)
adduser 用户名;如adduser s2001 ; 以新用户登录到系统
2.修改用户口令 passwd 用户名
3.控制文件属性
使用ls –l 查看文件属性
改变用户的所有权:chown 用户名 文件名
改变文件权限:chmod g+w 文件名;chmod o-r 文件名
或使用数字方式修改:如chmod 644文件名;chmod 755文件名
u (user用户),g ( group组),o (other其他); w 写访问权限,r 读访问权限, x 执行权限
4.查看相关命令的帮助:man 命令名
5.显示当前系统中已注册的用户信息:who
6.显示当前注册的用户信息:whoami
Tip:
Unix文件目录的属性显示格式:
如:-rw-rw-rw- 1 steve users 138 Apr 5 19:34 readme
drwxrwxrwx 3 steve users 80 Apr 5 19:43 dir1
三种权限: owner group others
第二部分 操作系统实验
实验1 Linux基本环境
1、实验目的
(1)熟悉Linux下的基本操作,学会使用各种Shell命令去操作Linux,对Linux有一个感性认识。
(2)学会使用vi编辑器编辑简单的C语言程序,并能对其编译和调试。
2、实验预备内容
(1)参阅相关Linux操作系统的安装手册,熟悉Linux的基本安装和配置;
(2)参阅相关Linux的命令参考手册,熟悉Linux下的操作命令。
3、实验内容
(1) 以root用户身份登陆,并使用“ls”,“cat”“cd”等命令来实现基本的文件操作并观察Linux文件系统的特点;
(2) 使用vi编辑器编写一C程序,并用gcc命令进行编译和链接,并用a.out来进行输出结果。
4、思考
(1)Linux系统在用户登陆和操作界面以及文件系统上有哪些特点?
实验2 进程管理
1、实验目的
(1)加深对进程概念的理解,明确进程和程序的区别。
(2)进一步认识并发执行的实质。
(3)分析进程竞争资源现象,学习解决进程互斥的方法。
(4)了解Linux系统中进程通信的基本原理。
2、实验预备内容
(1)阅读Linux的sched.h源文件,加深对进程管理概念的理解。
(2)阅读Linux的fork.c源文件,分析进程的创建过程。
3、实验内容
(1)进程的创建
编写一段源程序,使系统调用fork()创建两个子进程,当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示字符“a”;子进程分别显示字符“b”和字符“c”。试观察纪录屏幕上的显示结果,并分析原因。
(2)进程的控制
修改已编写的程序,将每个进程输出一个字符改为每个进程输出一句话,在观察程序执行时屏幕出现的现象,并分析原因。
如果在程序中使用调用lockf()来给每一个子进程加锁,可以实现进程之间的互斥,观察并分析出现的现象。
(3)①编写一段程序,使其现实进程的软中断通信。
要求:使用系统调用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上来的中断信号(即按DEL键);当捕捉到中断信号后,父进程用系统调用Kill()向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止:
Child Processll is Killed by Parent!
Child Processl2 is Killed by Parent!
父进程等待两个子进程终止后,输出如下的信息后终止
Parent Process is Killed!
②在上面的程序中增加语句signal (SIGNAL, SIG-IGN) 和signal (SIGQUIT, SIG-IGN), 观察执行结果,并分析原因。
(4)进程的管道通信
编制一段程序,实现进程的管理通信。
使用系统调用pipe()建立一条管道线;两个子进程P1和P2分别向管道中写一句话:
Child 1 is sending a message!
Child 2 is sending a message!
而父进程则从管道中读出来自于两个子进程的信息,显示在屏幕上。
要求父进程先接收子进程P1发来的消息,然后再接收子进程P2发来的消息。
4、思考
(1)系统是怎样创建进程的?
(2)可执行文件加载时进行了哪些处理?
(3)当首次调用新创建进程时,其入口在哪里?
(4)进程通信有什么特点?
实验3 进程间通信
1、实验目的
Linux系统的进程通信机构 (IPC) 允许在任意进程间大批量地交换数据。本实验的目的是了解和熟悉Linux支持的消息通讯机制及信息量机制。
2、实验预备内容
阅读Linux系统的msg.c、sem.c和shm.c等源码文件,熟悉Linux的三种机制。
3、实验内容
(1)消息的创建,发送和接收。
①使用系统调用msgget (), msgsnd (), msgrev (), 及msgctl () 编制一长度为1k的消息的发送和接收程序。
②观察上面的程序,说明控制消息队列系统调用msgctl () 在此起什么作用?
(2)共享存储区的创建、附接和段接。
使用系统调用shmget(),shmat(),sgmdt(),shmctl(),编制一个与上述功能相同的程序。
(3) 比较上述(1),(2)两种消息通信机制中数据传输的时间。
实验4 存储管理
1、实验目的
存储管理的主要功能之一是合理地分配空间。请求页式管理是一种常用的虚拟存储管理技术。
本实验的目的是通过请求页式存储管理中页面置换算法模拟设计,了解虚拟存储技术的技术特点,掌握请求页式存储管理的页面置换算法。
2、实验内容
(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(),分别进行初始化和产生随机数。例如:
srand ();
语句可初始化一个随机数;
a[0]=10*rand()/65535*319+1;
a[1]=10*rand()/65535*a[0];
语句可用来产生a[0]与a[1]中的随机数。
实验5 文件系统设计
1、实验目的
通过一个简单多用户文件系统的设计,加深理解文件系统的内部功能及内部实现。
2、实验内容
为linux系统设计一个简单的二级文件系统。要求做到以下几点:
(1)可以实现下列几条命令(至少4条);
login 用户登陆
dir 列文件目录
create 创建文件
delete 删除文件
open 打开文件
close 关闭文件
read 读文件
write 写文件
(2)列目录时要列出文件名、物理地址、保护码和文件长度;
(3)源文件可以进行读写保护。
3、实验提示
(1)首先应确定文件系统的数据结构:主目录、子目录及活动文件等。主目录和子目录都以文件的形式存放于磁盘,这样便于查找和修改。
(2)用户创建的文件,可以编号存储于磁盘上。如file0,file1,file2...并以编号作为物理地址,在目录中进行登记。
实验6 处理器调度
一、实验内容
选择一个调度算法,实现处理器调度。
二、实验目的
在采用多道程序设计的系统中,往往有若干个进程同时处于就绪状态。当就绪进程个数大于处理器数时,就必须依照某种策略来决定哪些进程优先占用处理器。本实验模拟在单处理器情况下的处理器调度,帮助学生加深了解处理器调度的工作。
三、实验题目
本实验有两个题,学生可选择其中的一题做实验。
第一题:设计一个按优先数调度算法实现处理器调度的程序。
[提示]:
(1) 假定系统有五个进程,每一个进程用一个进程控制块PCB来代表,进程控制块的格式为:
进程名 |
指针 |
要求运行时间 |
优先数 |
状态 |
其中,进程名——作为进程的标识,假设五个进程的进程名分别为P1,P2,P3,P4,P5。
指针——按优先数的大小把五个进程连成队列,用指针指出下一个进程的进程控制块的首地址,最后一个进程中的指针为“0”。
要求运行时间——假设进程需要运行的单位时间数。
优先数——赋予进程的优先数,调度时总是选取优先数大的进程先执行。
状态——可假设有两种状态,“就绪”状态和“结束”状态。五个进程的初始状态都为“就绪”,用“R”表示,当一个进程运行结束后,它的状态为“结束”,用“E”表示。
(2) 在每次运行你所设计的处理器调度程序之前,为每个进程任意确定它的“优先数”和“要求运行时间”。
(3) 为了调度方便,把五个进程按给定的优先数从大到小连成队列。用一单元指出队首进程,用指针指出队列的连接情况。例:
队首标志
K2
K1 |
P1 |
K2 |
P2 |
K3 |
P3 |
K4 |
P4 |
K5 |
P5 |
0 |
K4 |
K5 |
K3 |
K1 |
|||||
2 |
3 |
1 |
2 |
4 |
|||||
1 |
5 |
3 |
4 |
2 |
|||||
R |
R |
R |
R |
R |
|||||
PCB1 |
PCB2 |
PCB3 |
PCB4 |
PCB5 |
(4) 处理器调度总是选队首进程运行。采用动态改变优先数的办法,进程每运行一次优先数就减“1”。由于本实验是模拟处理器调度,所以,对被选中的进程并不实际的启动运行,而是执行:
优先数-1
要求运行时间-1
来模拟进程的一次运行。
提醒注意的是:在实际的系统中,当一个进程被选中运行时,必须恢复进程的现场,让它占有处理器运行,直到出现等待事件或运行结束。在这里省去了这些工作。
(5) 进程运行一次后,若要求运行时间¹0,则再将它加入队列(按优先数大小插入,且置队首标志);若要求运行时间=0,则把它的状态修改成“结束”(E),且退出队列。
(6) 若“就绪”状态的进程队列不为空,则重复上面(4)和(5)的步骤,直到所有进程都成为“结束”状态。
(7) 在所设计的程序中应有显示或打印语句,能显示或打印每次被选中进程的进程名以及运行一次后进程队列的变化。
(8) 为五个进程任意确定一组“优先数”和“要求运行时间”,启动所设计的处理器调度程序,显示或打印逐次被选中进程的进程名以及进程控制块的动态变化过程。
第二题:设计一个按时间片轮转法实现处理器调度的程序。
[提示]:
(1) 假定系统有五个进程,每一个进程用一个进程控制块PCB来代表。进程控制块的格式为:
进程名 |
指针 |
要求运行时间 |
已运行时间 |
状态 |
其中,进程名——作为进程的标识,假设五个进程的进程名分别为Q1,Q2,Q3,Q4,Q5。
指针——进程按顺序排成循环队列,用指针指出下一个进程的进程控制块的首地址,最后一个进程的指针指出第一个进程的进程控制块首地址。
要求运行时间——假设进程需要运行的单位时间数。
已运行时间——假设进程已经运行的单位时间数,初始值为“0”。
状态——有两种状态,“就绪”和“结束”,初始状态都为“就绪”,用“R”表示。当一个进程运行结束后,它的状态为“结束”,用“E”表示。
(2) 每次运行所设计的处理器调度程序前,为每个进程任意确定它的“要求运行时间”。
(3) 把五个进程按顺序排成循环队列,用指针指出队列连接情况。另用一标志单元记录轮到运行的进程。例如,当前轮到P2执行,则有:
标志单元
K2
K1 |
Q1 |
K2 |
Q2 |
K3 |
Q3 |
K4 |
Q4 |
K5 |
Q5 |
K2 |
K3 |
K4 |
K5 |
K1 |
|||||
2 |
3 |
1 |
2 |
4 |
|||||
1 |
0 |
0 |
0 |
0 |
|||||
R |
R |
R |
R |
R |
|||||
PCB1 |
PCB2 |
PCB3 |
PCB4 |
PCB5 |
(4) 处理器调度总是选择标志单元指示的进程运行。由于本实验是模拟处理器调度的功能,所以,对被选中的进程并不实际的启动运行,而是执行:
已运行时间+1
来模拟进程的一次运行,表示进程已经运行过一个单位的时间。
请同学注意:在实际的系统中,当一个进程被选中运行时,必须置上该进程可以运行的时间片值,以及恢复进程的现场,让它占有处理器运行,直到出现等待事件或运行满一个时间片。在这时省去了这些工作,仅用“已运行时间+1”来表示进程已经运行满一个时间片。
(5) 进程运行一次后,应把该进程的进程控制块中的指针值送到标志单元,以指示下一个轮到运行的进程。同时,应判断该进程的要求运行时间与已运行时间,若该进程的要求运行时间¹已运行时间,则表示它尚未执行结束,应待到下一轮时再运行。若该进程的要求运行时间=已运行时间,则表示它已经执行结束,应指导它的状态修改成“结束”(E)且退出队列。此时,应把该进程的进程控制块中的指针值送到前面一个进程的指针位置。
(6) 若“就绪”状态的进程队列不为空,则重复上面的(4)和(5)的步骤,直到所有的进程都成为“结束”状态。
(7) 在所设计的程序中应有显示或打印语句,能显示或打印每次选中进程的进程名以及运行一次后进程队列的变化。
(8) 为五个进程任意确定一组“要求运行时间”,启动所设计的处理器调度程序,显示或打印逐次被选中的进程名以及进程控制块的动态变化过程。
四、实验报告
(1) 实验题目。
(2) 程序中使用的数据结构及符号说明。
(3) 流程图。
(4) 打印一份源程序并附上注释。
(5) 打印程序运行时的初值和运行结果。要求如下:
ⅰ 进程控制块的初始状态。
ⅱ 选中运行的进程名以及选中进程运行后的各进程控制块状态。
对于ⅱ要求每选中一个进程运行后都要打印。
实验7 主存储器空间的分配和回收
一、实验内容
主存储器空间的分配和回收。
二、实验目的
一个好的计算机系统不仅要有一个足够容量的、存取速度高的、稳定可靠的主存储器,而且要能合理地分配和使用这些存储空间。当用户提出申请存储器空间时,存储管理必须根据申请者的要求,按一定的策略分析主存空间的使用情况,找出足够的空闲区域分配给申请者。当作业撤离或主动归还主存资源时,则存储管理要收回作业占用的主存空间或归还部分主存空间。主存的分配和回收的实现虽与主存储器的管理方式有关的,通过本实验帮助学生理解在不同的存储管理方式下应怎样实现主存空间的分配和回收。
三、实验题目
本实验模拟在两种存储管理方式下的主存分配和回收。
第一题:在可变分区管理方式下采用最先适应算法实现主存分配和实现主存回收。
[提示]:
可变分区方式是按作业需要的主存空间大小来分割分区的。当要装入一个作业时,根据作业需要的主存量查看是否有足够的空闲空间,若有,则按需要量分割一个分区分配给该作业;若无,则作业不能装入。随着作业的装入、撤离,主存空间被分成许多个分区,有的分区被作业占用,而有的分区是空闲的。例如:
操作系统 |
作业1 |
作业3 |
空闲区 |
作业2 |
空闲区 |
为了 说明哪些区是空闲的,可以用来装入新作业,必须要有一张空闲区说明表,格式如下:
起 址 |
长 度 |
状 态 |
|
第一栏 |
14 K |
12 K |
未 分 配 |
第二栏 |
32 K |
96 K |
未 分 配 |
M M |
空 表 目 |
||
空 表 目 |
|||
M M |
其中,起址——指出一个空闲区的主存起始地址。
长度——指出从起始地址开始的一个连续空闲的长度。
状态——有两种状态,一种是“未分配”状态,指出对应的由起址指出的某个长度的区域是空闲区;另一种是“空表目”状态,表示表中对应的登记项目是空白(无效),可用来登记新的空闲区(例如,作业撤离后,它所占的区域就成了空闲区,应找一个“空表目”栏登记归还区的起址和长度且修改状态)。由于分区的个数不定,所以空闲区说明表中应有适量的状态为“空表目”的登记栏目,否则造成表格“溢出”无法登记。
上述的这张说明表的登记情况是按提示(1)中的例所装入的三个作业占用的主存区域后填写的。
(2) 当有一个新作业要求装入主存时,必须查空闲区说明表,从中找出一个足够大的空闲区。有时找到的空闲区可能大于作业需要量,这时应把原来的空闲区变成两部分:一部分分给作业占用;另一部分又成为一个较小的空闲区。为了尽量减少由于分割造成的空闲区,而尽量保存高地址部分有较大的连续空闲区域,以利于大型作业的装入。为此,在空闲区说明表中,把每个空闲区按其地址顺序登记,即每个后继的空闲区其起始地址总是比前者大。为了方便查找还可使表格“紧缩”,总是让“空表目”栏集中在表格的后部。
(3) 采用最先适应算法(顺序分配算法)分配主存空间。
按照作业的需要量,查空闲区说明表,顺序查看登记栏,找到第一个能满足要求的空闲区。当空闲区大于需要量时,一部分用来装入作业,另一部分仍为空闲区登记在空闲区说明表中。
由于本实验是模拟主存的分配,所以把主存区分配给作业后并不实际启动装入程序装入作业,而用输出“分配情况”来代替。最先适应分配算法如图4-1。
(4) 当一个作业执行结束撤离时,作业所占的区域应该归还,归还的区域如果与其它空闲区相邻,则应合成一个较大的空闲区,登记在空闲区说明表中。例如,在提示(1)中列举的情况下,如果作业2撤离,归还所占主存区域时,应与上、下相邻的空闲区一起合成一个大的空闲区登记在空闲区说明表中。归还主存时的回收算法如图4-2。
(5) 请按最先适应算法设计主存分配和回收的程序。然后按(1)中假设主存中已装入三个作业,且形成两个空闲区,确定空闲区说明表的初值。现有一个需要主存量为6K的作业4申请装入主存;然后作业3撤离;再作业2撤离。请你为它们进行主存分配和回收,把空闲区说明表的初值以及每次分配或回收后的变化显示出来或打印出来。
第二题:在分页式管理方式下采用位示图来表示主存分配情况,实现主存空间的分配和回收。
[提示]:
(1) 分页式存储器把主存分成大小相等的若干块,作业的信息也按块的大小分页,作业装入主存时可把作业的信息按页分散存放在主存的空闲块中,为了说明主存中哪些块已经被占用,哪些块是尚未分配的空闲块,可用一张位示图来指出。位示图可由若干存储单元来构成,其中每一位与一个物理块对应,用0/1表示对应块为空闲/已占用。
(2) 假设某系统的主存被分成大小相等的64块,则位示图可用8个字节来构成,另用一单元记录当前空闲块数。如果已有第0,1,4,5,6,9,11,13,24,31,共10个主存块被占用了,那么位示图情况如下:
字 位 节 数 号 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
0 |
1 |
1 |
0 |
0 |
1 |
1 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
0 |
2 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
3 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
4 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
5 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
6 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
7 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
图 4-1 最先适应分配模拟算法
图 4-2 主存回收算法
(3) 当要装入一个作业时,根据作业对主存的需要量,先查当前空闲块数是否能满足作业要求,若不能满足则输出分配不成功。若能满足,则查位示图,找出为“0”的一些位,置上占用标志“1”,从“当前空闲块数”中减去本次占用块数。
按找到的计算出对应的块号,其计算公式为:
块号= j´8+i
其中,j表示找到的是第n个字节,I表示对应的是第n位。
根据分配给作业的块号,为作业建立一张页表,页表格式:
页 号 |
块 号 |
0 |
|
1 |
|
2 |
|
M M |
(4) 当一个作业执行结束,归还主存时,根据该作业的页表可以知道应归还的块号,由块号可计算出在位示图中的对应位置,把对应位的占用标志清成“0”,表示对应的块已成为空闲块。归还的块数加入到当前空闲块数中。由块号计算在位示图中的位置的公式如下:
字节号 j=[块号/8] ([ ]表示取整)
位数 i={块号/8} ({ }表示取余)
(5) 设计实现主存分配和回收的程序。假定位示图的初始状态如(2)所述,现有一信息量为5页的作业要装入,运行你所设计的分配程序,为作业分配主存且建立页表(格式如(3)所述)。然后假定有另一作业执行结束,它占用的块号为第4,5,6和31块,运行你所设计的回收程序,收回作业归还的主存块。
要求能显示和打印分配或回收前后的位示图和当前空闲块数,对完成一次分配后还要显示或打印为作业建立的页表。
四、实验报告
(1) 实验题目。
(2) 程序中使用的数据结构及符号说明。
(3) 流程图。
(4) 打印一份源程序并附上注释。
(5) 打印程序运行时的初值和运行结果,要求如下:
第一题:打印空闲区说明表的初始状态,作业4的申请量以及为作业4分配后的空闲区说明表状态;再依次打印作业3和作业2的归还量以及回收作业3,作业2所占主存后的空闲区说明表。
第二题:打印位示图和当前空闲块数的初值;要求装入的作业对主存的申请量,为作业分配后的位示图、当前空闲块数和页表;作业归还的块号、回收作业所占主存后的位示图和当前空闲块数。
第三部分 操作系统实验指导
实验2 指导
[实验内容]
1.进程的创建
〈任务〉
编写一段程序,使用系统调用fork( )创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符;父进程显示字符“a”,子进程分别显示字符“b”和“c”。试观察记录屏幕上的显示结果,并分析原因。
〈程序〉
#include<stdio.h>
main()
{
int p1,p2;
if(p1=fork()) /*子进程创建成功*/
putchar('b');
else
{
if(p2=fork()) /*子进程创建成功*/
putchar('c');
else putchar('a'); /*父进程执行*/
}
}
<运行结果>
bca(有时会出现abc的任意的排列)
分析:从进程执行并发来看,输出abc的排列都是有可能的。
原因:fork()创建进程所需的时间虽然可能多于输出一个字符的时间,但各个进程的时间片的获得却不是一定是顺序的,所以输出abc的排列都是有可能的。
2.进程的控制
<任务>
修改已编写好的程序,将每个程序的输出由单个字符改为一句话,再观察程序执行时屏幕上出现的现象,并分析其原因。如果在程序中使用系统调用lockf()来给每个程序加锁,可以实现进程之间的互斥,观察并分析出现的现象。
〈程序1〉
#include<stdio.h>
main()
{
int p1,p2,i;
if(p1=fork())
{
for(i=0;i<500;i++)
printf("parent%d\n",i);
wait(0); /* 保证在子进程终止前,父进程不会终止*/
exit(0);
}
else
{
if(p2=fork())
{
for(i=0;i<500;i++)
printf("son %d\n",i);
wait(0); /* 保证在子进程终止前,父进程不会终止*/
exit(0); /*向父进程信号0且该进程推出*/
}
else
{
for(i=0;i<500;i++)
printf(“grandchild %d\n",i); //引号有错
exit(0);
}
}
}
〈运行结果〉
parent….
son…
grandchild…
grandchild…
或grandchild
…son
…grandchild
…son
…parent
分析:由于函数printf()输出的字符串之间不会被中断,因此,每个字符串内部的字符顺序输出时不变。但是 , 由于进程并发执行时的调度顺序和父子进程的抢占处理机问题,输出字符串的顺序和先后随着执行的不同而发生变化。这与打印单字符的结果相同。
〈程序2〉
#include<stdio.h>
main()
{
int p1,p2,i;
if(p1=fork())
{
lockf(1,1,0);
for(i=0;i<500;i++)
printf("parent %d\n",i);
lockf(1,0,0);
wait(0); /* 保证在子进程终止前,父进程不会终止*/
exit(0);
}
else
{
if(p2=fork())
{
lockf(1,1,0);
for(i=0;i<500;i++)
printf("son %d\n",i);
lockf(1,0,0);
wait(0); /* 保证在子进程终止前,父进程不会终止*/
exit(0);
}
else
{
lockf(1,1,0);
for(i=0;i<500;i++)
printf("daughter %d\n",i);
lockf(1,0,0);
exit(0);
}
}
}
<运行结果〉
输出parent块,son块,grandchild块的顺序可能不同,但是每个块的输出过程不会被打断。
分析:因为上述程序执行时,lockf(1,1,0)锁定标准输出设备,lockf(1,0,0)解锁标准输出设备,在lockf(1,1,0)与lockf(1,0,0)中间的for循环输出不会被中断,加锁与不加锁效果不相同。
child process1 is killed by parent!
child process2 is killed by parent!
void waiting(),stop(),alarming();
signal(SIGINT,stop); /*接收到^c信号,转stop*/
signal(SIGALRM,alarming);/*接受SIGALRM
printf("parent process is killed!\n");
signal(SIGINT,SIG_IGN); /*忽略 ^c信号*/
printf("child process2 is killed by parent!\n");
signal(SIGINT,SIG_IGN); /*忽略^c信号*/
printf("child process1 is killed by parent!\n");
不做任何操作等待五秒钟父进程回在子进程县推出后退出,并打印退出的顺序;或者点击ctrl+C后程序退出并打印退出的顺序。
printf("child process 1 is killed !by parent\n");
printf("child process 2 is killed !by parent\n");
printf("parent process is killed\n");
编制一段程序,实现进程的管道通信。使用系统调用pipe()建立一条管道线。两个子进程p1和p2分别向通道个写一句话:
child1 process is sending message!
child2 process is sending message!
char outpipe[100],inpipe[100];
sprintf(outpipe,"child 1 process is sending message!");
write(fd[1],outpipe,50); /*向管道写长为50字节的串*/
sprintf(outpipe,"child 2 process is sending message!");
read(fd[0],inpipe,50); /*从管道中读长为50字节的串*/
child1 process is sending message!
child2 process is sending message!
使用系统调用msgget( ), megsnd( ), msgrev( )及msgctl()编制一长度为1K的消息发送和接收的程序 。
(1) 为了便于操作和观察结果,用一个 程序为“引子”,先后fork( )两个子进程,SERVER和CLIENT,进行通信。
(4) 父进程在 SERVER和 CLIENT均退出后结束。
#define MSGKEY 75 /*定义关键词MEGKEY*/
msgqid=msgget(MSGKEY,0777|IPC_CREAT);
msgsnd(msgqid,&msg,1030,0); /*发送消息msg入msgid消息队列*/
msgqid=msgget(MSGKEY,0777|IPC_CREAT); /*由关键字获得消息队列*/
msgrcv(msgqid,&msg,1030,0,0); /*从队列msgid接受消息msg*/
}while(msg.mtype!=1); /*消息类型为1时,释放队列*/
Server交替发送和接收消息.最后一次接收两条消息. Client 和Server 分别发送和接收了10条消息,与预期设想一致
使用系统调用shmget(),sgmat(),smgdt(),shmctl()编制一个与上述功能相同的程序.
(1)为了便于操作 和观察结果,用一个 程序为“引子”,先后fork( )两个子进程,SERVER 和 CLIENT,进行通信。
#define SHMKEY 75 /*定义共享区关键词*/
shmid=shmget(SHMKEY,1024, 0777|IPC_CREAT); /*获取共享区,长度1024,关键词SHMKEY*/
addr=shmat(shmid,0,0); /*共享区起始地址为addr*/
printf("(client)sent\n"); /*打印(client)sent*/
printf("(server)received\n%d",*addr); /*服务进程使用共享区*/
shmid=shmget(SHMKEY,1024,0777|IPC_CREAT); /*创建共享区*/
addr=shmat(shmid,0,0); /*共享区起始地址为addr*/
运行的结果和预想的完全一样。但在运行的过程中,发现每当client发送一次数据后,server要等大约0.1秒才有响应。同样,之后client又需要等待大约0.1秒才发送下一个数据。
由于两种机制实现的机理和用处都不一样,难以直接进行时间上的比较。如果比较其性能,应更加全面的分析。
设计一个虚拟存储区和内存工作区,并使用下列算法计算访问命中率.
本实验的程序设计基本上按照实验内容进行。即首先用srand()和rand()函数定义和产生指令序列,然后将指令序列变换成相应的页地址流,并针对不同的算法计算出相应的命中率。相关定义如下:
其中pn 为页号,pfn为面号, counter为一个周期内访问该页面的次数, time为访问时间.
typedef struct pfc_struct pfc_type;
pfc_type pfc_struct[total_vp],*freepf_head,*busypf_head;
(1)Void initialize( ):初始化函数,给每个相关的页面赋值.
(2)Void FIFO( ):计算使用FIFO算法时的命中率.
(3)Void LRU( ):计算使用LRU算法时的命中率.
(4)Void OPT( ):计算使用OPT算法时的命中率.
(5)Void LFU( ):计算使用LFU算法时的命中率.
(6)Void NUR( ):计算使用NUR算法时的命中率.
(1)int a[total_instruction]: 指令流数据组.
(2)int page[total_instruction]: 每条指令所属的页号.
(3)int offset[total_instruction]: 每页装入10条指令后取模运算页号偏移值.
#define total_instruction 320 /*指令流长*/
#define clear_period 50 /*清0周期*/
int pfn; //页面框架号 physical frame number
pl_type pl[total_vp]; /*页面线性结构---指令序列需要使用地址*/
typedef struct pfc_struct /*页面控制结构,调度算法的控制结构*/
pfc_type pfc[total_vp], *freepf_head, *busypf_head, *busypf_tail;
int diseffect, a[total_instruction]; /* a[]为指令序列*/
int page[total_instruction], offset[total_instruction];/*地址信息*/
int NUR(int); //not use recently
srand(10*getpid()); /*由于每次运行时进程号不同,故可用来作为初始化随机数队列的“种子”*/
s=(float)319*rand( )/32767/32767/2+1; /*正态分布*/
for(i=0;i<total_instruction;i+=4) /*产生指令队列*/
printf("When i==%d,Error,s==%d\n",i,s);
a[i+2]=(float)a[i]*rand( )/32767/32767/2; /*执行前地址指令m*/
s=(float)(318-a[i+2])*rand( )/32767/32767/2+a[i+2]+2;
printf("a[%d+2],a number which is :%d and s==%d\n",i,a[i+2],s);
for (i=0;i<total_instruction;i++) /*将指令序列变换成页地址流*/
for(i=4;i<=32;i++) /*用户内存工作区从4个页面到32个页面*/
printf("---%2d page frames---\n",i);
/*初始化相关数据结构 total_pf表示内存的块数 */
pl[i].pfn=INVALID; /*置页面控制结构中的页号,页面为空*/
pl[i].counter=0; /*页面控制结构中的访问次数为0*/
for(i=0;i<total_pf-1;i++) /*建立pfc[i-1]和pfc[i]之间的链接*/
pfc[total_pf-1].pfn=total_pf-1;
freepf_head=&pfc[0]; /*空页面队列的头指针为pfc[0]*/
int FIFO(int total_pf) /*先进先出算法total_pf:用户进程的内存页面数*/
initialize(total_pf); /*初始化相关页面控制用数据结构*/
busypf_head=busypf_tail=NULL; /*忙页面队列头,队列尾链接*/
for(i=0;i<total_instruction;i++)
if(pl[page[i]].pfn==INVALID) /*页面失效*/
if(freepf_head==NULL) /*无空闲页面*/
pl[busypf_head->pn].pfn=INVALID;
freepf_head=busypf_head; /*释放忙页面队列的第一个页面*/
freepf_head->next=NULL; /*表明还是缺页*/
pl[page[i]].pfn=freepf_head->pfn;
freepf_head->next=NULL; /*使busy的尾为null*/
busypf_tail=busypf_head=freepf_head;
busypf_tail->next=freepf_head;
printf("FIFO:%6.4f\n",1-(float)diseffect/320);
int LRU (int total_pf) /*最近最久未使用算法least recently used*/
int min,minj,i,j,present_time; /*minj为最小值下标*/
for(i=0;i<total_instruction;i++)
if(pl[page[i]].pfn==INVALID) /*页面失效*/
if(freepf_head==NULL) /*无空闲页面*/
for(j=0;j<total_vp;j++) /*找出time的最小值*/
if(min>pl[j].time&&pl[j].pfn!=INVALID)
freepf_head=&pfc[pl[minj].pfn]; //腾出一个单元
pl[page[i]].pfn=freepf_head->pfn; //有空闲页面,改为有效
pl[page[i]].time=present_time;
freepf_head=freepf_head->next; //减少一个free 页面
pl[page[i]].time=present_time; //命中则增加该单元的访问次数
printf("LRU:%6.4f\n",1-(float)diseffect/320);
int NUR(int total_pf ) /*最近未使用算法Not Used recently count表示*/
for(i=0;i<total_instruction;i++)
if (pl[page[i]].pfn==INVALID) /*页面失效*/
if(freepf_head==NULL) /*无空闲页面*/
if(pl[dp].counter==0&&pl[dp].pfn!=INVALID)
pl[page[i]].pfn=freepf_head->pfn;
freepf_head=freepf_head->next;
printf("NUR:%6.4f\n",1-(float)diseffect/320);
int OPT(int total_pf) /*最佳置换算法*/
int i,j, max,maxpage,d,dist[total_vp];
for(i=0;i<total_instruction;i++)
if(pl[page[i]].pfn==INVALID) /*页面失效*/
if(freepf_head==NULL) /*无空闲页面*/
if((pl[j].pfn!=INVALID)&&(dist[j]==32767))
freepf_head=&pfc[pl[maxpage].pfn];
pl[page[i]].pfn=freepf_head->pfn;
freepf_head=freepf_head->next;
printf("OPT:%6.4f\n",1-(float)diseffect/320);
/*该算法时根据已知的预测未知的,least frequency Used是最不经常使用置换法*/
for(i=0;i<total_instruction;i++)
if(pl[page[i]].pfn==INVALID) /*页面失效*/
if(freepf_head==NULL) /*无空闲页面*/
if(min>pl[j].counter&&pl[j].pfn!=INVALID)
freepf_head=&pfc[pl[minpage].pfn];
pl[page[i]].pfn=freepf_head->pfn; //有空闲页面,改为有效
freepf_head=freepf_head->next; //减少一个free 页面
pl[page[i]].counter=pl[page[i]].counter+1;
printf("LFU:%6.4f\n",1-(float)diseffect/320);
4 page framesFIFO:0.2562LRU:0.2531OPT:0.3031LFU:0.2812NUR:0.2812
5 page framesFIFO:0.2969LRU:0.2906OPT:0.3500LFU:0.3219NUR:0.3094
6 page framesFIFO:0.3375LRU:0.3281OPT:0.3844LFU:0.3375NUR:0.3344
7 page framesFIFO:0.3563LRU:0.3563OPT:0.4031LFU:0.3563NUR:0.3500
8 page framesFIFO:0.3937LRU:0.3750OPT:0.4531LFU:0.3937NUR:0.3719
9 page framesFIFO:0.4219LRU:0.4094OPT:0.4844LFU:0.4156NUR:0.4062
10 page framesFIFO:0.4375LRU:0.4313OPT:0.5062LFU:0.4313NUR:0.4250
11 page framesFIFO:0.4813LRU:0.4625OPT:0.5531LFU:0.4500NUR:0.4656
12 page framesFIFO:0.5406LRU:0.4875OPT:0.5687LFU:0.4938NUR:0.4875
13 page framesFIFO:0.5500LRU:0.5188OPT:0.5969LFU:0.5062NUR:0.5437
14 page framesFIFO:0.5594LRU:0.5531OPT:0.6344LFU:0.5281NUR:0.5469
15 page framesFIFO:0.5687LRU:0.5844OPT:0.6687LFU:0.5469NUR:0.5813
16 page framesFIFO:0.5781LRU:0.5938OPT:0.6813LFU:0.5719NUR:0.5969
17 page framesFIFO:0.5906LRU:0.6156OPT:0.6969LFU:0.6156NUR:0.6156
18 page framesFIFO:0.6156LRU:0.6312OPT:0.7156LFU:0.6344NUR:0.6531
19 page framesFIFO:0.6687LRU:0.6656OPT:0.7344LFU:0.6531NUR:0.6719
20 page framesFIFO:0.6875LRU:0.6969OPT:0.7500LFU:0.6719NUR:0.6906
21 page framesFIFO:0.6906LRU:0.7094OPT:0.7688LFU:0.6969NUR:0.7188
22 page framesFIFO:0.7125LRU:0.7219OPT:0.7969LFU:0.7156NUR:0.7344
23 page framesFIFO:0.7156LRU:0.7406OPT:0.8125LFU:0.7250NUR:0.7812
24 page framesFIFO:0.7281LRU:0.7625OPT:0.8187LFU:0.7406NUR:0.7719
25 page framesFIFO:0.7469LRU:0.7750OPT:0.8344LFU:0.7594NUR:0.8000
26 page framesFIFO:0.8125LRU:0.8000OPT:0.8500LFU:0.7812NUR:0.8063
27 page framesFIFO:0.8313LRU:0.8187OPT:0.8594LFU:0.8031NUR:0.8281
28 page framesFIFO:0.8438LRU:0.8375OPT:0.8688LFU:0.8344NUR:0.8469
29 page framesFIFO:0.8688LRU:0.8531OPT:0.8750LFU:0.8562NUR:0.8562
30 page framesFIFO:0.8781LRU:0.8719OPT:0.8781LFU:0.8750NUR:0.8688
31 page framesFIFO:0.8938LRU:0.8750OPT:0.8844LFU:0.8844NUR:0.8906
32 page framesFIFO:0.9000LRU:0.9000OPT:0.9000LFU:0.9000NUR:0.9000
比较上述5种算法,以OPT算法的命中率最高,NUR算法次之,再就是LFU算法和LRU算法,其次是FIFO算法。就本问题,在15页之前,FIFO的命中率比LRU的高。
4 page framesFIFO:0.2594LRU:0.2562OPT:0.2687LFU:0.2437NUR:0.2625
5 page framesFIFO:0.3000LRU:0.3000OPT:0.3000LFU:0.2969NUR:0.2875
6 page framesFIFO:0.3375LRU:0.3281OPT:0.3281LFU:0.3094NUR:0.3281
7 page framesFIFO:0.3563LRU:0.3563OPT:0.3688LFU:0.3312NUR:0.3469
8 page framesFIFO:0.4031LRU:0.4094OPT:0.3875LFU:0.3406NUR:0.3781
9 page framesFIFO:0.4156LRU:0.4281OPT:0.4156LFU:0.3656NUR:0.4125
10 page framesFIFO:0.4281LRU:0.4469OPT:0.4313LFU:0.3750NUR:0.4406
11 page framesFIFO:0.4531LRU:0.4688OPT:0.4594LFU:0.4281NUR:0.4656
12 page framesFIFO:0.4656LRU:0.4813OPT:0.4906LFU:0.4375NUR:0.4938
13 page framesFIFO:0.4750LRU:0.5000OPT:0.5219LFU:0.4625NUR:0.5312
14 page framesFIFO:0.4906LRU:0.5125OPT:0.5375LFU:0.4938NUR:0.5500
15 page framesFIFO:0.5312LRU:0.5250OPT:0.5625LFU:0.5281NUR:0.5563
16 page framesFIFO:0.5406LRU:0.5625OPT:0.5813LFU:0.5531NUR:0.5844
17 page framesFIFO:0.5906LRU:0.5813OPT:0.6188LFU:0.5750NUR:0.6031
18 page framesFIFO:0.6000LRU:0.5906OPT:0.6344LFU:0.5906NUR:0.6250
19 page framesFIFO:0.6312LRU:0.6156OPT:0.6438LFU:0.6219NUR:0.6438
20 page framesFIFO:0.6406LRU:0.6344OPT:0.6625LFU:0.6438NUR:0.6750
21 page framesFIFO:0.6969LRU:0.6594OPT:0.6875LFU:0.6656NUR:0.6937
22 page framesFIFO:0.7000LRU:0.6781OPT:0.7125LFU:0.6813NUR:0.6844
23 page framesFIFO:0.7156LRU:0.6906OPT:0.7312LFU:0.7188NUR:0.6969
24 page framesFIFO:0.7438LRU:0.7219OPT:0.7531LFU:0.7438NUR:0.7469
25 page framesFIFO:0.7594LRU:0.7562OPT:0.7656LFU:0.7656NUR:0.7719
26 page framesFIFO:0.7750LRU:0.7812OPT:0.7937LFU:0.7781NUR:0.7781
27 page framesFIFO:0.8125LRU:0.7969OPT:0.8094LFU:0.8125NUR:0.7969
28 page framesFIFO:0.8344LRU:0.8313OPT:0.8281LFU:0.8313NUR:0.8406
29 page framesFIFO:0.8406LRU:0.8594OPT:0.8531LFU:0.8375NUR:0.8406
30 page framesFIFO:0.8625LRU:0.8781OPT:0.8750LFU:0.8562NUR:0.8594
31 page framesFIFO:0.8812LRU:0.8812OPT:0.8906LFU:0.8781NUR:0.8656
32 page framesFIFO:0.9000LRU:0.9000OPT:0.9000LFU:0.9000NUR:0.9000
从结果可以看出,FIFO的命中率竟然比OPT的还高。至于为什么,请探讨。
为Linux系统设计一个简单的二级文件系统。要求做到以下几点:
unsigned int i_into; /*磁盘i节点标号*/
unsigned int i_count; /*引用计数*/
unsigned short di_number; /*关联文件书,当为0时,则删除该文件*/
unsigned short di_mode; /*存取权限*/
unsigned short di_uid; /*磁盘i节点用户*/
unsigned short di_gid; /*磁盘i节点组*/
Unsigned int di_addr[NADDR]; /*物理块号*/
unsigned short di_number; /*关联文件数*/
unsigned short di_mode; /*存取权限*/
unsigned long di_size; /*文件大小*/
unsigned int di_addr[NADDR]; /*物理块号*/
unsigned short s_isize; /*i节点块块数*/
unsigned long s_fsize; /*数据块块数*/
unsigned int s_nfree; /*空闲块块数*/
unsigned short s_pfree; /*空闲块指针*/
unsigned int s_free[NICFREE]; /*空闲块堆栈*/
unsigned int s_ninode; /*空闲i节点数*/
unsigned short s_pinode; /*空闲i节点指针*/
unsigned int s_inode[NICINOD]; /*空闲i节点数组*/
unsigned int s_rinode; /*铭记i节点*/
unsigned int f_count; /*引用计数*/
struct inode *f_inode; /*指向内存节点*/
unsigned long f_off; /*读/写指针*/
unsigned short u_default_mode;
unsigned short u_uid; /*用户标志*/
unsigned short u_gid; /*用户组标志*/
unsigned short u_ofile[NOFILE]; /*用户打开表*/
(9)搜索当前目录下文件的函数iname( )(详细描述略)。
(19)文件系统格式化函数format( )(详细描述略)。
(20)进入文件系统函数install( )(详细描述略)。
由上述的描述过乘可知,该文件系统实际是为用户提供一个解释执行相关命令的环境。主程序中的大部分语句都被用来执行相应的命令。
下面我们给出每个过程的相关C语言程序。读者也可以使用这些子过程,编写一个用Shell控制的文件系统界面。
本文件系统程序用编写makefile管理工具进行管理。其内容如下:
***********************************************************************/
/*******************************************
*******************************************/
filsys:main.o iallfre.o ballfre.o name.o access.o log.o close.o creat.o delete.o dir.o
open.o rdwt.o format.o install.o halt.o cc-o filsys main.o iallfre.o ballfre.o
name.o access.o log.o close.o creat.o delete.o dir.o open.o format.o install.o halt.o
igetput.o: igetput.c filesys.h
iallfre.o: iallfre.c filesys.h
ballfre.o: ballfre.c filesys.h
install.o: install.c filesys.h
int lockf(files,function,size)
其中:files是文件描述符:function是锁定和解锁;1表示锁定,0表示解锁。size是锁定和解锁的字节数,若用0,表示从文件的当前位置到文件尾。
获得一个消息的描述符,该描述符指定一个消息队列以便用于其他系统调用。
其中:msgid是该系统调用返回的描述符,失败则返回-1;flag 本身由操作允许权和控制命令值相“或”得到。
IP_EXCL |0400 是否该队列的创建应是互斥的;等。
5、msgrcv(id,msgp,size,type,flag):
int msgrcv(id,msgp,size,type,flag)
struct sgbuf{long mtpe;chat mtext[];};
count=msgrcv(id,msgp,size,type,flag)
其中:id是用来存放欲接收消息的拥护数据结构的地址;size是msgp中数据数组的大小; type是用户要读的消息类型:
type为负:接收小于或等于type绝对值的最低类型的第一个消息。
flag规定倘若该队列无消息,核心应当做什么事,如果此时设置了IPC_NOWAIT标志,则立即返回,若在flag中设置了MSG_NOERROR,且所接收的消息大小大于size,核心截断所接受的消息。
查询一个消息描述符的状态,设置它的状态及删除一个消息描述符。
其中:函数调用成功时返回0,调用不成功时返回-1。id用来识别该消息的描述符;cmd规定命令的类型。
IPC_SET为这个消息序列设置有效的用户和小组标识及操作允许权和字节的数量。
{struct ipc_perm msg_perm; /*许可权结构*/
ushort msg_qbytes; /*队列上最大字节数*/
ushort msg_lspid; /*最后发送消息的PID*/
ushort msg_lrpid; /*最后接收消息的PID*/
time_t msg__stime; /*最后发送消息的时间*/
time_t msg_rtime; /*最后接收消息的时间*/
{shot patl;long pad2} /*由系统使用*/
其中:size是存储区的字节数,key和flag与系统调用msgget中的参数含义相同。
如:shmid=shmget(key,size,(IPC_CREAT|0400));
语法格式:virtaddr=shmat(id,addr,flag)
其中,当调用成功时,返回0值,调用不成功,返回-1,addr是系统调用shmat所返回的地址。
对与共享存储区关联的各种参数进行操作,从而对共享存储区进行控制。
其中:调用成功返回0,否则返回-1。id为被共享存储区的标识符。cmd规定操作的类型。规定如下:
IPC_STAT:返回包含在指定的shmid相关数据结构中的状态信息,并且把它放置在用户存储区中的*but指针所指的数据结构中。执行此命令的进程必须有读取允许权。
IPC_SET:对于指定的shmid,为它设置有效用户和小组标识和操作存取权。
IPC_RMID:删除指定的shmid以及与它相关的共享存储区的数据结构。
SHM_LOCK:在内存中锁定指定的共享存储区,必须是超级用户才可以进行此项操作。
{struct ipc_perm shm_perm; /*允许权结构*/
ushort shm_lpid; /*最后操作的进程id;*/
ushort shm_cpid; /*创建者的进程id;*/
操作系统实验指导书(完整版)相关推荐
- 计算机操作系统32,计算机操作系统实验指导书32138
计算机操作系统实验指导书32138 (22页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 14.9 积分 <计算机操作系统>实验指导书程科白素 ...
- 计算机操作系统实验指导linux版,操作系统实验指导书(linux版).doc
操作系统实验指导书(linux版) <操作系统>实验指导书 实验学时:16 适用专业:计算机科学与技术 实验一:进程和线程的创建 1. 在linux下编写一个应用程序,命名为an_ch2_ ...
- 算法设计与分析实验指导(完整版)
算法设计与分析实验指导 文章目录 算法设计与分析实验指导 1. 快速排序及第k小数 1.1 快速排序 1.1.1 Implementation 1 1.1.2 算法特性分析 1.1.3 Improve ...
- linux 实验指导书,linux操作系统实验指导书新 - 图文
巢湖学院 -p 指定程序识别码,并列出该程序的状况. p 此参数的效果和指定\参数相同,只在列表格式方面稍有差异. r 只列出现行终端机正在执行中的程序. -t 指定终端机编号,并列出属于该终端机的程 ...
- 利用who,w,ps和top等指令查看linux下的进程执行情况.,UNIXLINUX操作系统实验指导书...
STAT 该进程的状态.其中S代表休眠状态:D代表不可中断的休眠状态:R代表运行状态:Z代表僵死状态:T代表停止或跟踪状态. TIME 该进程自启动以来所占用的总CPU时间.如果进入的是累计模式,那么 ...
- 计算机操作系统指导书,《计算机操作系统》实验指导书-2015
q.num++; System.out.println(\已生产第:\个产品!\ try { Thread.currentThread().sleep(100); } catch (Interrupt ...
- 数据科学、管理科学系课程教学课件——FineReport实验指导书节选====明细表、分组表、交叉表
数据科学.管理科学系的数据大屏.数据报表.商务智能.管理信息系统等课程教学,只需简单的数据库基础,解放学生码代码的时间,用更真实的企业案例,更灵活的将思维落地.本节讲述的是通用报表的分析案例:明细 ...
- 数据科学、管理科学系课程教学课件——FineReport实验指导书节选====证券公司年度计划表
数据科学.管理科学系课程教学,0基础也能掌握,本节讲述的是金融经管类专业的数据科学.管理科学系课程案例:证券公司年度计划表 使用数据 fredu数据库:成交量表,年收入趋势表,市值表,收盘价表 ...
- 数据科学、管理科学系课程教学课件——FineReport实验指导书节选====利润中心
数据科学.管理科学系课程教学,0基础也能掌握,本节讲述的是金融经管类专业的数据科学.管理科学系课程案例:利润中心 使用数据 以下数据(Multi1除外)在各模板中均为SELECT * FROM ...
最新文章
- 解决无法删除的dll文件
- 怎么用计算机算亩数,怎样用手机测量亩数?
- 【Python】Python环境配置保姆教程(Anaconda、Jupyter、GPU环境)!
- android启用hdcp_如何在Android上启用优先收件箱(和设置仅重要通知)
- 5G精华问答 | 5G是否会“逼退”4G?
- python优化网站_[练习] 用PYTHON来优化网站中的图片
- Linux学习之CentOS(五)----网卡的配置
- cass地籍参数设置命令_想成为一名厉害的测绘员?南方Cass教程+插件+课件不可少!...
- 5种方式,判断一个数组中是否包含某个元素
- Steroids上的SQL Server Express Edition
- 房子怎么拆除_新规,可能拆除农村这4类房子,每户家庭可能获得40万
- leetcode·单调栈
- 2007年春节读书心得
- win10远程桌面连接凭据怎么设置_win10远程桌面怎么保存密码?win10让远程桌面记住密码的方法...
- 绘制管理组织结构图方法介绍
- 20220313_朴素贝叶斯
- 计算机网络常见的协议之ARP协议
- 原创整理!计算机常用【快捷键、缩写、英语单词】不定更
- 肯德基微信小程序连接服务器异常,微信小程序平台常见问题及解决方案
- Pycharm永久激活七步走