操作系统实验报告
实验一:熟悉Linux命令及进程管理
一、 实验目的
1.加深对进程概念的理解,明确进程和程序的区别
2.进一步认识并发执行的实质
3.分析进程征用资源的现象,学习解决进程互斥的方法
二、 实验内容
1.熟悉Linux的基本操作
2.熟悉全屏幕编辑器vi的使用和操作、gcc编译器的使用
3.熟悉系统调用命令
4.运行getpid、fork、exit、wait、sleep的示例程序,并分析运行结果
5.通过运行验证性程序1、程序2、程序3、程序4,并分析运行结果,熟悉进程管理
6.编写程序:
1、要求程序运行时,系统中存在如下的进程树结构,写出程序源代码及程序运行结果并在进程树的相应进程节点上标上进程号。
2、对以上程序4进行修改,使得修改以后的程序在运行过程中三个进程不会被相互打断。
用到的知识:
lockf
lockf(files,function,size):
用作锁定文件的某些段或者整个文件,本函数适用的头文件为:
#include<unistd.h>
参数定义:
int lockf(files,function,size)
int files,function;
long size;
其中:files是文件描述符:function是锁定和解锁;1表示锁定,0表示解锁。Size是锁定或解锁的字节数,若用0,表示从文件的当前位置到文件尾。
若要防止一个进程在运行过程中被打断,可以用lockf(1,1,0)对整个进程进行加
锁,结束前用lockf(1,0,0)做解锁操作,以便其他进程的运行。
三、 代码及运行结果分析
(一)熟悉Linux的基本操作,熟悉Vi编辑器和gcc编译器的使用 运用telnet 92.168.0.249命令远程登录服务器,用户名e0662366,密码a登录帐号。
输入命令ls,查看所有文件目录名:
[e06620336@localhost e06620336]$ ls
a.out fork_test like.c wu.c wu4.c wuyaping1.c wyp4.c
exit_test1 fork_test.c look.c wu1.c wu5.c wyp1.c zombie.c exit_test1.c getpid_test wait1.c wu2.c wu6.c wyp2.c
fork.c getpid_test.c wait2.c wu3.c wuyaping.c wyp3.c
输入命令ll,列出该文件的所有文件信息,包括时间,是否可读写:
第一个字符代表文件类型,c开头代表字符串文件,b代表块文件,d开头代表目录
三组八进制位,分别表示读、写、操作的权限。第一组表示本人对目录下文件的权限;第二组表示本组对目录下文件的权限;第三组表示其他组对目录下文件的权限。
ll与ls的区别是ll更加详细地列出文件的信息,包括隐藏的文件,而ls只是列出了文件的显式文件。
[e06620336@localhost e06620336]$ ll
total 136
-rwxr-xr-x 1 e06620336 e066203 12069 Jun 2 2009 a.out
-rwxr-xr-x 1 e06620336 e066203 11659 Mar 24 2009 exit_test1 -rw-r--r-- 1 e06620336 e066203 118 Mar 24 2009 exit_test1.c -rw-r--r-- 1 e06620336 e066203 42 Mar 24 2009 fork.c -rwxr-xr-x 1 e06620336 e066203 11884 Mar 24 2009 fork_test -rw-r--r-- 1 e06620336 e066203 335 Mar 24 2009 fork_test.c -rwxr-xr-x 1 e06620336 e066203 11670 Mar 24 2009 getpid_test -rw-r--r-- 1 e06620336 e066203 110 Mar 24 2009 getpid_test.c -rw-r--r-- 1 e06620336 e066203 281 Apr 28 2009 like.c -rw-r--r-- 1 e06620336 e066203 208 Apr 28 2009 look.c -rw-r--r-- 1 e06620336 e066203 437 Mar 24 2009 wait1.c -rw-r--r-- 1 e06620336 e066203 307 Mar 24 2009 wait2.c -rw-r--r-- 1 e06620336 e066203 267 Apr 28 2009 wu.c -rw-r--r-- 1 e06620336 e066203 425 Jun 2 2009 wu1.c -rw-r--r-- 1 e06620336 e066203 328 Apr 28 2009 wu2.c -rw-r--r-- 1 e06620336 e066203 322 Apr 28 2009 wu3.c -rw-r--r-- 1 e06620336 e066203 264 Apr 28 2009 wu4.c -rw-r--r-- 1 e06620336 e066203 257 Apr 28 2009 wu5.c -rw-r--r-- 1 e06620336 e066203 384 Apr 28 2009 wu6.c
-rw-r--r-- 1 e06620336 e066203 432 Jun 2 2009 wuyaping.c -rw-r--r-- 1 e06620336 e066203 421 Jun 2 2009 wuyaping1.c -rw-r--r-- 1 e06620336 e066203 882 Jun 2 2009 wyp1.c -rw-r--r-- 1 e06620336 e066203 391 Jun 2 2009 wyp2.c -rw-r--r-- 1 e06620336 e066203 640 Jun 2 2009 wyp3.c -rw-r--r-- 1 e06620336 e066203 397 Jun 2 2009 wyp4.c -rw-r--r-- 1 e06620336 e066203 308 Mar 24 2009 zombie.c
[e06620336@localhost e06620336]$
[e06620336@localhost e06620336]$ cd ..
[e06620336@localhost home]$ Cd .. 返回上一级目录
[e06620336@localhost home]$ cd / Cd / 一步到达根目录
[e06620336@localhost /]$ ls
bin dev home lib misc opt root tftpboot usr boot etc initrd lost+found mnt proc sbin tmp var
[e06620336@localhost /]$
[e06620336@localhost e06620336]$ more like.c 直接查看文件内容 #include<stdio.h>
main()
{
int p1,p2;
while((p1=fork())= =-1);
if(p1= =0)
printf("b.My process ID is %d",getpid());
else
{
while((p2=fork())= =-1);
if(p2==0)
printf(隆"c.My process ID is %d",getpid());
else printf("a.My process ID is %d",getpid());
}
}
[e06620336@localhost e06620336]$ less like.c 分页查看文件内容 #include<stdio.h>
main()
{
int p1,p2;
while((p1=fork())= =-1);
if(p1= =0)
printf("b.My process ID is %d",getpid());
else
{
while((p2=fork())= =-1);
if(p2==0)
printf(&&"c.My process ID is %d",getpid());
else printf("a.My process ID is %d",getpid());
}
}
like.c (END)
less和more的区别是less可以回头浏览,而more则只能往后浏览。
查看进程
[e06620336@localhost e06620336]$ who
root :0 Dec 3 13:53
root pts/0 Dec 3 13:54 (:0.0)
e0662013 pts/3 Dec 3 13:58 (192168un.)
e0662011 pts/8 Dec 3 14:02 (192168un.)
e0662021 pts/2 Dec 3 14:02 (192168un.)
e0662032 pts/7 Dec 3 14:02 (192168un.)
e0662031 pts/12 Dec 3 14:03 (192168un.)
e0662011 pts/15 Dec 3 14:03 (192168un.)
全屏幕文本编辑器
Vi hello.c
输入I,进入插入模式,输入程序
按esc退出,按shift+;键,进入末行模式,wq写入并退出VI编辑器。
此时hello.c还没保存
[e06620336@localhost e06620336]$ gcc hello.c
//gcc编译器对hello.c进行编译并产生a,out的执行文件。
[e06620336@localhost e06620336]$ ls
a.out fork_test hello.c wait1.c wu2.c wu6.c wyp2.c exit_test1 fork_test.c like.c wait2.c wu3.c wuyaping.c wyp3.c exit_test1.c getpid_test look.c wu.c wu4.c wuyaping1.c wyp4.c
fork.c getpid_test.c w1.c wu1.c wu5.c wyp1.c zombie.c
[e06620336@localhost e06620336]$ ./a.out //执行a.out文件
hell0 world![e06620336@localhost e06620336]$ gcc hello.c -o hello
//看到实验结果“hello world!”,此时再用gcc编译器产生hello.c的执行文件hello
[e06620336@localhost e06620336]$ ls
a.out fork_test.c like.c wu.c wu5.c wyp2.c
exit_test1 getpid_test look.c wu1.c wu6.c wyp3.c
exit_test1.c getpid_test.c w1.c wu2.c wuyaping.c wyp4.c
fork.c hello wait1.c wu3.c wuyaping1.c zombie.c
//产生的hello的执行文件
fork_test hello.c wait2.c wu4.c wyp1.c
[e06620336@localhost e06620336]$ ./hello //执行hello文件
hell0 world![e06620336@localhost e06620336]$ //执行的结果
(二)验证实验:getpid、fork、exit、sleep、wait
getpid验证
Getpid返回当前进程的进程ID
fork验证
#include<sys/types.h>
#include<unistd.h>
main()
{
pid_t pid; /*此时仅有一个进程*/
pid=fork(); /*此时已经有两个进程在同时运行*/
if(pid<0) /*负值,输出错误信息*/
printf("error in fork!");
else if(pid==0) /*子进程,返回ID值*/
printf("I am the child process, my process ID is %d\n",getpid());
;
Else /*父进程,返回ID值*/
printf("I am the parent process, my process ID is %d\n",getpid());
);
}
"test.c" [已转换] 13L, 279C 已写入
[e06620336@192168un e06620336]$ gcc -o test test.c //生成test的执行文件
[e06620336@192168un e06620336]$ ./test //执行test文件
I am the child process, my process ID is 8542
I am the parent process, my process ID is 8541
[e06620336@192168un e06620336]$
执行新的应用程序时,我们先调用fork,再调用exec,这样就好像通过执行一个应用程序创建了一个新进程。
exit的验证
#include<stdlib.h>
main()
{
printf("this process will exit!\n");
exit(0); /*终止进程*/
printf("never be displayed!\n");
}
"test1.c" [新] 7L, 117C 已写入
[e06620336@192168un e06620336]$ gcc -o test1 test1.c
[e06620336@192168un e06620336]$ ./test1
this process will exit!
//从运行结果看出,进程在exit(0);处终止,进入僵尸状态,导致后面的“never be displayed!”没有输出
[e06620336@192168un e06620336]$
wait的验证
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
main()
{
pid_t pc,pr;
pc=fork();
if(pc<0) /* 如果出错 */
printf("error ocurred!\n");
else if(pc==0){
printf("This is child process with pid of %d\n",getpid());
sleep(10);
}
else{
pr=wait(NULL);
printf("I catched a child process with pid of %d\n",pr);
}
exit(0);
}
"test2.c" [已转换] 20L, 365C 已写入
[e06620336@192168un e06620336]$ gcc -o test2 test2.c
[e06620336@192168un e06620336]$ ./test2
This is child process with pid of 9157
I catched a child process with pid of 9157
[e06620336@192168un e06620336]$
zombie的验证
#include <sys/types.h>
#include <unistd.h>
main()
{
pid_t pid;
pid=fork();
if(pid<0) /* 如果出错 */
printf("error occurred!\n");
else if(pid==0) /* 如果是子进程 */
exit(0);
else /* 如果是父进程 */
sleep(60);/* 休眠60秒,这段时间里,父进程什么也干不了 */
/*这段时间内,子进程已经退出,父进程休眠,父进程不能收集
到子进程的信息,这样就保持了60秒的僵尸状态*/
wait(NULL);/* 收集僵尸进程 */
}
"test3.c" [已转换] 15L, 194C 已写入
[e06620336@192168un e06620336]$ gcc -o test3 test3.c
[e06620336@192168un e06620336]$ ./test3 &
[1] 9831
[e06620336@192168un e06620336]$ ps -ax //列出系统内的进程
//标记为Z的进程就是僵尸进程; S代表休眠状态;D代表不可中断的休眠状态;R代表运行状态;Z代表僵死状态;T代表停止或跟踪状态
?? ??
9831 pts/23 S 0:00 ./test3
9832 pts/23 Z 0:00 [test3 <defunct>] //僵尸进程
9847 pts/23 R 0:00 ps -ax
(三)验证程序1、2、3、4,编写程序5、6
程序1
#include "stdio.h"
main()
{int i,j,k;
if (i=fork()) /*为父进程,i>0*/
{j=wait(); /*j为子进程的ID号*/
printf("Parent Process!\n");
printf("i=%d,j=%d,k=%d\n",i,j);
}
else /*为子进程, i=0*/
{k=getpid(); /*k为子进程的ID号*/
printf("Child Process!\n");
printf("i=%d,k=%d\n\n",i,k);
}
}
"program1.c" [新] 14L, 207C 已写入
[1]+ Exit 104 ./test3
[e06620336@192168un e06620336]$ gcc -o program1 program1.c
[e06620336@192168un e06620336]$ ./program1
Child Process!
i=0,k=9988 //i=0表示当前进程是子进程,子进程没有自己的子进程,所以i=0,k是子 进程的ID号
Parent Process!
i=9988,j=9988,k=134513639 //i=9988表示当前进程是父进程,fork()的值为子进程的ID 9988, j返回的是wait()的值,j=9988,表示父进程的子进程ID为9988
进程树:N为父进程,M为子进程
程序2
#include<stdio.h>
main()
{
int p1,p2;
while((p1=fork())==-1); /*出错*/
if(p1==0) /*子进程*/
printf("b.My process ID is %d",getpid());/*输出子进程b的ID*/
else
{
while((p2=fork())==-1); /*出错*/
if(p2==0) /*子进程*/
printf("c.My process ID is %d",getpid()); /*输出子进程c的ID*/ else printf("a.My process ID is %d",getpid()); /*输出父进程a的ID*/
}
}
"program2.c" 15L, 273C 已写入
[e06620336@192168un e06620336]$ gcc -o program2 program2.c
[e06620336@192168un e06620336]$ ./program2
b.My process ID is 10493c.My process ID is 10494a.My process ID is 10492
//运行结果是父进程a的ID为10492,子进程b的ID为10493,子进程c的ID为10494 进程树:
程序3
main() {int m,n,k; m=fork();
printf("PID:%d\t",getpid());
printf("The return value of fork():%d\t\t",m); printf("he\n"); n=fork();
printf("PID:%d\t",getpid());
printf("The return value of fork():%d\t\t",n); printf("ha\n"); k=fork();
printf("PID:%d\t",getpid());
printf("The return value of fork():%d\t\t",k); printf("ho\n"); }
"program3.c" [已转换] 15L, 328C 已写入
[e06620336@192168un e06620336]$ gcc -o program3 program3.c [e06620336@192168un e06620336]$ ./program3
PID:10613 The return value of fork():10614 he PID:10615 The return value of fork():0 ha PID:10613 The return value of fork():10615 ha PID:10617 The return value of fork():0 ho PID:10613 The return value of fork():10617 ho [e06620336@192168un e06620336]$
PID:10614 The return value of fork():0 he PID:10618 The return value of fork():0 ha
//b
//czi //c //ezi //e //bzi //dzi
PID:10619 The return value of fork():0 ho //hzi PID:10618 The return value of fork():10619 ho //h PID:10614 The return value of fork():10618 ha //d PID:10620 The return value of fork():0 ho //fzi PID:10614 The return value of fork():10620 ho //f PID:10616 The return value of fork():0 ho //gzi PID:10615 The return value of fork():10616 ho //g
从运行结果看,父进程和子进程运行的顺序是随机的,且容易在运行过程中被打断。且每一次fork都会在当前进程上创建子进程,由1->2->4->8的规律进行进程创建。每次调用fork,由fork创建的子进程也会运行fork后面的程序。这是因为fork把当前的情况拷贝一份送到新创建的子进程中。
程序树:
程序4
#include<stdio.h> main() {
int p1,p2,i;
while((p1=fork())==-1); if(p1==0)
for(i=0;i<50000;i++)
printf("son%d\n",i);
else
{
while((p2=fork())==-1);
if(p2==0)
for(i=0;i<50000;i++)
printf("daughter%d\n",i);
else
for(i=0;i<50000;i++)
printf("parent%d\n",i);
}
}
"program4.c" [已转换] 19L, 259C 已写入
[e06620336@192168un e06620336]$ gcc -o program4 program4.c
[e06620336@192168un e06620336]$
观察运行结果可以发现,子进程和父进程的执行顺序是随机的,也就是说,在运行过程中,进程是会被打断的。
程序5
main()
{int m,n,k;
m=fork();
printf("PID:%d\t",getpid());
printf("The return value of fork():%d\t\t",m);
printf("he\n");
n=fork();
printf("PID:%d\t",getpid());
printf("The return value of fork():%d\t\t",n);
printf("ha\n");
if(m>0&&n>0){
k=fork();
printf("PID:%d\t",getpid());
printf("The return value of fork():%d\t\t",k); printf("ho\n"); } }
"program5.c" [已转换] 18L, 345C 已写入
[e06620336@192168un e06620336]$ gcc -o program5 program5.c [e06620336@192168un e06620336]$ ./program5
PID:11019 The return value of fork():0 he PID:11018 The return value of fork():11019 he PID:11021 The return value of fork():0 ha PID:11018 The return value of fork():11021 ha PID:11022 The return value of fork():0 ho PID:11018 The return value of fork():11022 ho [e06620336@192168un e06620336]$
PID:11020 The return value of fork():0 ha PID:11019 The return value of fork():11020 ha
//bzi //b //dzi //d //ezi //e //czi //c
程序树:
程序6
main() {
int p1,p2,i;
while((p1=fork())==-1); if(p1==0){ /*子进程1*/ lockf(1,1,0); /*锁定*/ for(i=0;i<50000;i++) printf("son%d\n",i);
lockf(1,0,0); /*解锁*/
}
else /*父进程*/
{
lockf(1,1,0); /*锁定*/
while((p2=fork())==-1);
if(p2==0){ /*父进程创建的子进程2*/
lockf(1,1,0); /*锁定*/
for(i=0;i<50000;i++)
printf("daughter%d\n",i);
lockf(1,0,0); /*解锁*/
}
else{ /*子进程1创建的子进程3*/
lockf(1,1,0); /*锁定*/
for(i=0;i<50000;i++)
printf("parent%d\n",i);
lockf(1,0,0); /*解锁*/
}
lockf(1,0,0); /*解锁*/
}
}
"program6.c" [已转换] 33L, 402C 已写入
[e06620336@192168un e06620336]$ gcc -o program6 program6.c
[e06620336@192168un e06620336]$ ./program6
通过对每个进程的锁定和解锁的成对操作,保证进程在运行期间不会被打断,从程序的运行结果来看,该方法是正确的。
四、 实验心得
通过这次使用,比较系统地掌握了一些常用的Linux命令,并且练习了怎样使用Vi编辑器和gcc编译器。另外通过对几个验证性实验的操作和观察,总结系统调用命令的用途,解决几个比较基础的问题,为以后的实验打下基础。总的来说,这次实验获益良多。
《计算机操作系统》实验报告班级:姓名:学号:实验一进程控制与描述一、实验目的通过对Windows2000编程,进一步熟悉操作系统的…
操作系统实验报告实验名称理解UNIXLINUXShell及UNIX的进程树成绩专业班级计科姓名学号联系电话实验日期20xx年12月…
目录实验一进程的创建2实验二进程控制3实验三进程的管道通信4实验四消息通信6实验五进程调度算法8实验六FIFO页面置换算法12实验…
操作系统实验报告学号姓名班级实验一实验报告实验名称并发程序设计实验1实验目的掌握在程序中创建新进程的方法观察并理解多道程序并发执行…
《操作系统原理》实验报告院(部):管理工程学院专业:信息管理与信息系统实验项目:实验一二三五班级:信管102姓名:学号:目录引言.…
1-1:通过这次小实验,是我更加了解Linux一些常用指令的操作以及其作用,对于一个刚开始接触lniux操作系统的初学者来说非常有…
学号:姓名:班级:在本学期的计算机操作系统这门课学习当中,为了更好的了解操作系统相关知识,我们通过OSLab平台做了几个实验。在实…
《计算机操作系统》实验报告班级:姓名:学号:实验一进程控制与描述一、实验目的通过对Windows2000编程,进一步熟悉操作系统的…
操作系统实验总结学号学生姓名专业班级111进程创建UNIX中进程既是一个独立拥有资源的基本单位又是一个独立调度的基本单位一个进程实…
武汉理工大学学生实验报告书实验课程名称操作系统开课学院计算机科学与技术学院指导老师姓名刘军学生姓名学生专业班级20xx20xx学年…