操作系统1.doc
《操作系统1.doc》由会员分享,可在线阅读,更多相关《操作系统1.doc(35页珍藏版)》请在冰点文库上搜索。
院系:
计算机科学学院___
专业:
自动化
年级:
2008
课程名称:
操作系统
指导教师:
__刘晶
组号:
组员:
田长刚(08064086)
陆师(08064089)
涂润(08064085)
2010年12月15日
实验1Linux系统用户接口和编程界面实验(4学时)
一.实验目的
1.熟悉使用Linux字符界面、窗口系统的常用命令。
2.熟悉运用Linux常用的编程工具。
3.熟悉运用Linux的在线帮助系统。
4.掌握在Linux操作系统环境上编辑、编译、调试、运行一个C语言程序的全过程。
二.实验内容与步骤
1.登录Linux系统
步骤1:
启动linux系统,在登陆界面的左下方单击“会话”,在屏幕弹出的菜单中选择会话方式“GNOME”。
步骤2:
登录用户名:
root密码:
123456。
步骤3:
在菜单中单击“系统工具”->“终端”命令,显示终端窗口。
步骤4:
运行常用命令(login,logout,exit,halt,shutdown,pwd,cd,mkdir,rmdir,cat,cp,mv,rm,ls,chmod,find,grep,more,sort,gzip,unzip,tar,rpm,man,info,--help)
ls:
显示目录类容,命令格式ls【选项】【目录或文件】
cd:
改变工作目录命令,命令格式cd【路径】例子:
返回上一级目录cd··
进入子目录cdxh
mkdir:
创建目录命令,例子:
在当前目录下建立默认权限并且名字为student的子目录mkdirstudent
rmdir:
删除目录命令,例子:
删除当前目录先名为dir的空子目录rmdirdir
cat:
建立和显示文件命令,例子:
显示文本文件sdwa。
Txt的内容
cat–bsdwa。
txt
cp:
文件和目录复制命令命令格式cp【选项】源文件或目录目标文件或目录
rm:
删除文件和目录命令例子:
删除当前目录下的文件file1.txtrmfile1.txt
2.使用Linux的vi编辑器
用vi编辑一个打印“Hello,IamaCprogram”字串的C语言程序,然后编译并运行它。
熟悉gcc、gdb等编译器、调试器的使用。
步骤1:
在系统提示符后键入命令“vi”,后面跟上想要编辑或者建立的文件名,就可以进入vi环境了。
在vi环境中编辑一个打印“Hello,IamaCprogram”字串的C语言程序。
然后键入“:
wq”命令退出vi。
步骤2:
调用C语言编译器编译源程序
命令格式:
gcc[-o可执行文件名]源文件名
步骤3:
运行程序
使用命令行:
./可执行程序名
指导:
1.进入linux的文本模式之后,在命令行键入vihello.c然后回车。
下面作一些简单的解释:
首先vi命令是打开vi编辑器。
后面的hello.c是用户即将编辑的c文件名字,注意扩展名字是.c;当然,vi编辑器功能很强,可以用它来编辑其它格式的文件,比如汇编文件,其扩展名字是.s;也可以直接用vi打开一个新的未命名的文件,当保存的时候再给它命名,只是这样做不很方便。
2.最基本的命令i:
当进入刚打开的文件时,不能写入信息,这时按一下键盘上的i键(insert),插入的意思,就可以进入编辑模式了。
如下图所示:
3.a与i是相同的用法
4.当文件编辑完后,需要保存退出,这时需要经过以下几个步骤:
1)按一下键盘上的Esc键;2)键入冒号(:
),紧跟在冒号后面是wq(意思是保存并退出)。
如果不想保存退出,则在第二步键入冒号之后,键入!
q(不带w,机尾部保存)。
如下图所示:
5.退出vi编辑器的编辑模式之后,要对刚才编写的程序进行编译。
W的配合使用
【注意:
如果不知道现在处于什么模式,可以多按几次Esc键,以便确定进入命令模式】
Vi的常用命令
【1】进入vi的命令
Vifilename:
打开或新建文件,并将光标置于第一行首
Vi+nfilename:
打开文件,并将光标置于第n行首
Vi+filename:
打开文件,并将光标置于最后一行行首
【2】插入文本类命令
i:
在光标所在位置前插入新的字符
o:
在当前行之下心开一行
【3】修改和删除命令
X:
删除光标前的字符
x:
删除光标后的字符
dd:
删除当前行
r:
替换光标所在字符
6.编译的命令是:
gcc-ohellohello.c,gcc编译器就会为我们生成一个hello的可执行文件。
其中gcc是c的编译器。
命令行中gcc表示我们是用gcc来编译我们的源程序,-o选项表示我们要求编译器给我们输出的可执行文件名为hello,而hello.c是我们的源程序文件。
最后一步是运行程序,在命令行界面输入:
./hello
具体操作:
用I命令进行编辑,类容如下
#include
intmain(){
print(“hello\n”);
return();
}
2.按ESC,在vi命令模式下使用:
wq命令进行保存,并退出编辑器
3.进入hello.c所在目录,使用gcc-ohellohello.c对源文件进行编译
4.要查看执行结果,使用./hello就可以在屏幕上看见结果了
实验2
进程控制
实
验
内
容
1Linux系统常用进程管理命令的使用(操作系统观察级)
2Linux系统常用进程创建与管理的系统调用(原码阅读与系统编程级)
3Windows平台常用进线程控制API(原码阅读与系统编程级)
实
验
要
求
学会对Linux系统常用进程管理命令的使用
学会创建简单常用进程,以及掌握一些常用的系统调用
了解Windows平台常用进线程控制API
小组成员
姓名
学号
组内分工
教师评分
Linux系统常用进程管理命令的使用(操作系统观察级)
Linux系统常用进程创建与管理的系统调用(原码阅读与系统编程级)
Windows平台常用进线程控制API(原码阅读与系统编程级)
小
组
成
绩
评
定
教师签名:
年月日
实
验
原
理
步
骤
(
算
法
流
程
)
一、Linux系统常用进程管理命令的使用(操作系统观察级)
1、ps命令
功能:
显示正在执行的进程的信息
格式:
ps[options][pids]
常用选项:
_l以长列表的形式列出
_a显示其他用户的进程
_e显示环境
_r只显示正在运行的程序
2、jobs命令
功能:
列出当前正在运行的作业信息,该命令没有选项和参数。
格式:
job
3、kill命令
功能:
终止(或撤销)一个进程。
格式:
kill[options]pid
常用选项:
_l输出信号名列表
_p指kill只输出已命名pid,而且不送信号给它
-s<信号名>指出欲发出的信号,信号十一信号名或数字给出的。
4、&命令
功能:
将进程放到后台运行
方法:
在要运行的程序命令的最后加上“&”字符。
例子:
yes>/dev/null&
[1]-yes的作业号
164-进程标识号
5、bg命令
功能:
把前台作业放到后台:
例如:
对2号作业
6、fg命令
功能:
把后台作业放到前台
例如:
对2号作业
二、Linux系统常用进程创建与管理的系统调用(原码阅读与系统编程级)
fock()函数创建进程
exec()系列可以将一个可执行的二进制文件覆盖在新进程的用户级上下文的存储空间上,以更改新进程的用户级上下文。
exec()没有建立一个与调用进程并发的子进程,而是用新进程取代了原来进程。
wait()
等待子进程运行结束。
如果子进程没有完成,父进程一直等待。
wait()将调用进程挂起,直至其子进程因暂停或终止而发来软中断信号为止。
如果在wait()前已有子进程暂停或终止,则调用进程做适当处理后便返回。
exit()
终止进程的执行。
例如:
编写一段程序,父进程通过建立子进程在同一显示器上同时分别循环显示“我是父进程”和“我是子进程”。
#include
#include
#include
#include
#include printf("I am the child progress,my progress ID is %d",getpid());~
main()
{
pid_t pid;
/*此时仅有一个进程*/
pid=fork();
/*此时已经有两个进程在同时运行*/
if(pid<0) /*进程没有创建成功*/
printf("error in fork!
");
else if(pid==0) /*子进程*/
printf("I am the child process, my process ID is %d",getpid());
else /*父进程*/
printf("I am the parent process, my process ID is %d",getpid());
}
三、Windows平台常用进线程控制API(原码阅读与系统编程级)
WCHARlpPath[]=L"notepad.exe";
STARTUPINFOsi={sizeof(si)};
//设置STARTF_USESHOWWINDOW标记,使得STARTUPINFO结构的wShowWindow字段有效
PROCESS_INFORMATIONpi;
BOOLbStatus=CreateProcess
(NULL,lpPath,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
实
验
结
果
及
分
析
一、各种目录命令的运用
二、父进程通过建立子进程在同一显示器上同时分别循环显示“我是父进程”和“我是子进程”
三、通过修改lpPath[]=L"notepad.exe"中双引号的内容来产生不同的进程。
心
得
体
会
通过这次试验,掌握了Linux系统常用进程管理命令的使用方法。
学会了Linux系统常用进程的创建,以及各种常用系统函数的调用。
了解了Windows平台常用进线程控制API;初步学会了对原码的阅读。
l
实验1
简单进程通信
实
验
内
容
管道是进程间通信的一个基本途径,进程可以通过管道进行信息传输;管道就像它的名字一样,数据从它的一头流向另一头(当然有的情况也可以从另一头流向这一头)。
本次试验我们要做的试验内容主要有两点:
l1熟悉什么是管道,了解Unix/Linux支持的管道通信方式
l2读懂TXT文本上面的程序
l3能够自己编写用管道通行的程序实现管道间的进程通信
实
验
要
求
1用系统调用pipe()建立一个管道,两个子进程分别向管道各写一句话Child1issendingamessage!
, Child2issendingamessage!
父进程从管道中读出来自两个子进程的信息并显示。
2要求在子进程没有完全完成输入任务是父进程不得输出,只有子进程完全将信息输入到管道后,父进程才能将管道里面的信息输出。
3父进程显示管道里面的信息的时候应该先显示进程1的信息,然后再显示进程2的信息
小组成员
姓名
学号
组内分工
教师评分
小
组
成
绩
评
定
教师签名:
年月日
实
验
原
理
步
骤
(
算
法
流
程
)
#include
main()
{
inti,r,p1,p2,fd[2];
charbuf[50],s[50];/*两个缓冲,分别入管道和出管道*/
pipe(fd);/*父进程建立管道*/
while(p1=fork()==-1);/*创建子进程,此处中断,子进程为父进程副本*/
if(p1==0)/*说明此时处于子进程*/
{
lockf(fd[1],1,0);/*加锁锁定写入端*/
sprintf(buf,"childprocessp1issendingmessage!
\n");
printf("childprocessp1!
\n");
write(fd[1],buf,50);/*把buf中的字符写入管道*/
sleep(5);
lockf(fd[1],0,0);/*释放管道写端*/
exit(0);
}
else/*说明此时处于父进程*/
{
while(p2=fork()==-1);/*创建另外一个子进程*/
if(p2==0)
{
lockf(fd[1],1,0);
sprintf(buf,"childprocessp2issendingmessage!
\n");
printf("childprocessp2!
\n");
write(fd[1],buf,50);
lockf(fd[1],0,0);
exit(0);
}
wait(0);/*父进程阻塞自己,直到子进程完成*/
if(r=read(fd[0],s,50==-1))
printf("can'treadpipe\n");
elseprintf("%s\n",s);
exit(0);
}
}
pipe(fd)创建管道
p1=fork()==-1
判断P1是否等于-1
N
Y
创建子进程2,子进程2读数据
创建子进程P1,子进程1读数据
父进程读取BUF缓冲区里面的内容并显示
实
验
结
果
及
分
析
实验结果:
实验结果是输出BUF中的内容,先输出的子进程1的内容,后输出子进程2的内容。
正确的事业结果的建立在正确的实验步骤上面,对于实验的结果。
我感觉的很正常
结果分析:
首先我建立两个缓冲区BUF和S前者用于输入缓冲,后者用于输出缓存
其次我正确的调用pipe函数先后创建了两个子进程,P1,P2,并且这两进程先后向管道写进信息。
再次在读取信息之前我确保读入已经结束,这一点很重要,另外管道是半双工的机制,这一点在进行试验的时候,也已经注意到了
另外我通过学习管道的知识又懂得了:
管道存在基本的通信限制,它只能用于有亲缘关系的进程,比如实验里面的子进程与父进程之间的通信,同时管道很多时候被认为是半双工的,即数据的流向是单向的,只能从输入缓冲区写入从输出缓冲区读出
管道的读写操作不是原子的,在读写操作的过程中可能被打断。
比如创建子进程的过程中父进程就会被中断
道存在于内存之中,它有一个大小为PIPE_BUF的缓冲区,这个数值通常是操作系统的一个页的大小。
比如试验中Buf和S缓冲区
管道与标准输入输出联合使用往往可以写出具有简单易用的多进合作应用,典型的应用是协同进程(或过滤进程)。
管道只能被两个进程使用,一个写,一个读;如何一个管道有多个进程写或多个进程读,之后的读写函数将失败,并设置相应的errno。
当管道的写端存在时,如果请求的字节数目大于PIPE_BUF,则返回管道中现有的数据字节数,如果请求的字节数目不大于PIPE_BUF,则返回管道中现有数据字节数(此时,管道中数据量小于请求的数据量);或者返回请求的字节数(此时,管道中数据量不小于请求的数据量)。
注:
(PIPE_BUF在include/linux/limits.h中定义,不同的内核版本可能会有所不同。
Posix.1要求PIPE_BUF至少为512字节,redhat7.2中为4096)。
心
得
体
会
通过管道的进程通信实验我懂得了:
管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;
管道只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
一个进程向管道中写的内容被管道另一端的进程读出。
写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。
实验2
Linux统常用进程创建与管理的系统调用
实
验
内
容
1.通过查阅参考书或者上网找资料,熟悉/usr/src/linux(注意:
这里最后一级目录名可能是个含具体内核版本号和“linux”字符串的名字)下各子目录的内容,即所含Linux源代码的情况。
阅读Linux的sched.h原码文件,加深对进程管理概念的理解。
阅读Linux的fork.c原码文件,分系进程的创建过程。
2.编写一段程序,使系统调用fork()创建两个子进程。
让每一个进程在屏幕上显示一个字符:
父进程显示“a”;子进程分别显示“b”和“c”。
观查屏幕上的显示结果,并分析原因。
3.修改已编写的程序,将每个进程输出一个字符改为每个进程输出一句话,再观查程序的执行时屏幕上出现的现象,并分析原因。
如果在程序中使用系统调用lockf()来给每一个进程加锁,可以实现进程之间的互斥,观查并分析原因。
实
验
要
求
小组成员
姓名
学号
组内分工
教师评分
小
组
成
绩
评
定
教师签名:
年月日
实
验
原
理
步
骤
(
算
法
流
程
)
#include
main()
{intp1,p
while(p1==-1)
p1=fock();//创建子进程2;
p1=fock();
if(p1==0)//子进程创建成功
printf(“Iamthechild1”);
else{
p2=fork();
while(p2==-1);
p2=fork();//创建另一个子进程
if(p2==0)//子进程创建成功
printf(“Iamthechild2”);
else
printf(“Iamtheparent”);//父进程执行
}
}
p1=fock()
判断P1是否为0
N
Y
P2=fork()
创建子进程P1
判断P2是否是0
N
Y
创建子进程P2
返回父进程
实
验
结
果
及
分
析
这个实验中我们成功的创建了两个子进程,P1P2
这个实验中我在主程序中用了两个fork调用成功的生成了两个子进程,P1,P2
这个实验之所以成功的关键在于成功的调用了fork调用,
intp1,p
while(p1==-1)
p1=fock();//创建子进程2;
p1=fock();
if(p1==0)//子进程创建成功
printf(“Iamthechild1”);
这个程序段成功的生成了第一个子进程P1。
else{
p2=fork();
while(p2==-1);
p2=fork();//创建另一个子进程
if(p2==0)//子进程创建成功
printf(“Iamthechild2”);
else
printf(“Iamtheparent”);//父进程执行
}
这一段程序成功的生成了子进程P2
心
得
体
会
通过这个实验我学会了,子进程创建一般方法,我懂得了如何编程,如何用相关的知识解决问题
我很成功
实验3.1
进程同步与互斥(生产者消费者问题)
实
验
内
容
以生产者/消费者模型为依据,在WindowsXP环境下创建一个控制台进程,在该进程中创建n个线程模拟生产者和消费者,实现进程(线程)的同步与互斥。
掌握基本的同步互斥算法,理解