操作系统上实验报告3汇总.docx
《操作系统上实验报告3汇总.docx》由会员分享,可在线阅读,更多相关《操作系统上实验报告3汇总.docx(13页珍藏版)》请在冰豆网上搜索。
![操作系统上实验报告3汇总.docx](https://file1.bdocx.com/fileroot1/2022-10/11/17c33918-f56b-4eea-9424-5851d966fc60/17c33918-f56b-4eea-9424-5851d966fc601.gif)
操作系统上实验报告3汇总
操作系统实验三报告
实验题目:
进程管理及进程通信
实验环境:
虚拟机Linux操作系统
实验目的:
1.利用Linux提供的系统调用设计程序,加深对进程概念的理解。
2.体会系统进程调度的方法和效果。
3.了解进程之间的通信方式以及各种通信方式的使用。
实验内容:
例程1:
利用fork()创建子进程
#include
#include
#include
main()
{
inti;
if(fork())
i=wait(0);
/*父进程执行的程序段*/
/*等待子进程结束*/
printf("Itisparentprocess.\n");
printf("Thechildprocess,IDnumber%d,isfinished.\n",i);
}
else{
printf("Itischildprocess.\n");
sleep(10);
/*子进程执行的程序段*/
exit
(1);
/*向父进程发出结束信号*/
}
}
运行结果:
思考:
子进程是如何产生的?
又是如何结束的?
子进程被创建后它的运行环境是怎
样建立的?
答:
子进程是通过函数fork()创建的,通过exit()函数自我结束的,子进程被创建后核心将为其分配一个进程表项和进程标识符,检查同时运行的进程数目,并且拷贝进程表项的数据,由子进程继承父进程的所有文件。
例程2:
循环调用fork()创建多个子进程
#include
#include
#include
main()
{inti,j;
printf(“Mypidis%d,myfather’spidis%d\n”,getpid()
getppid());
for(i=0;i<3;i++)
if(fork()==0)
printf(“%dpid=%dppid=%d\n”,i,getpid(),getppid());
else
{j=wait(0);
Printf(“%d:
Thechile%disfinished.\n”,getpid(),j);
}
}
运行结果:
思考:
画出进程的家族树。
子进程的运行环境是怎样建立的?
反复运行此程序
看会有什么情况?
解释一下。
答:
子进程的运行环境是由将其创建的父进程而建立的,反复运行程序会发现每个进程标识号在不断改变,这是因为同一时间有许多进程在被创建。
例程3:
创建子进程并用execlp()系统调用执行程序的实验
#include
#include
main()
{
intchild_pid1,child_pid2,child_pid3;
intpid,status;
setbuf(stdout,NULL);
child_pid1=fork();/*创建子进程1*/
if(child_pid1==0)
{execlp("echo","echo","childprocess1",(char*)0);/*子进程1启动其它程序*/
perror("exec1error.\n");
exit
(1);
}
child_pid2=fork();/*创建子进程2*/
if(child_pid2==0)
{execlp("date","date",(char*)0);/*子进程2启动其它程序*/
perror("exec2error.\n");
exit
(2);
}
child_pid3=fork();/*创建子进程3*/
if(child_pid3==0)
{execlp("ls","ls",(char*)0);/*子进程3启动其它程序*/
perror("exec3error.\n");
exit(3);
}
puts("Parentprocessiswaitingforchileprocessreturn!
");
while((pid=wait(&status))!
=-1)/*等待子进程结束*/
{if(child_pid1==pid)/*若子进程1结束*/
printf("childprocess1terminatedwithstatus%d\n",(status>>8));
else
{if(child_pid2==pid)/*若子进程2结束*/
printf("childprocess2terminatedwithstatus%d\n",(status>>8));
else
{if(child_pid3==pid)/*若子进程3结束*/
printf("childprocess3terminatedwithstatus%d\n",(status>>8));
}
}
}
puts("Allchildprocessesterminated.");
puts("Parentprocessterminated.");
exit(0);
}
运行结果:
思考:
子进程运行其他程序后,进程运行环境怎样变化的?
反复运行此程序看会有什么情况?
解释一下。
答:
子进程运行其他程序后,这个进程就完全被新程序代替。
由于并没有产生新进程所以进程标识号不改变,除此之外旧进程的其它信息,代码段,数据段,栈段等均被新程序的信息所代替。
新程序从自己的main()函数开始运行。
反复运行此程序发现结束的先后次序是不可预知的,每次运行结果都不一样。
原因是当每个子进程运行其他程序时,他们的结束随着其他程序的结束而结束,所以结束的先后次序在改变。
例程4:
观察父、子进程对变量处理的影响
#include
#include
#include
intgloba=4;
intmain()
{
pid_tpid;
intvari=5;
printf("beforefork.\n");
if((pid=fork())<0)
{
}
printf("forkerror.\n");
exit(0);
else
if(pid==0)
{
/*子进程执行*/
globa++;
vari--;
printf("Child%dchangedthevariandgloba.\n",getpid());
}
else
{
/*父进程执行*/
wait(0);
printf("Parent%ddidnotchangedthevariandgloba.\n",getpid());
}
printf("pid=%d,globa=%d,vari=%d\n",getpid(),globa,vari);
/*都执行*/
exit(0);
}
运行结果:
思考:
子进程被创建后,对父进程的运行环境有影响吗?
解释一下。
答:
子进程被创建后,对父进程的运行环境无影响,因为当子进程在运行时,它有自己的代码段和数据段,这些都可以作修改,但是父进程的代码段和数据段是不会随着子进程数据段和代码段的改变而改变的。
例程5:
管道通信的实验
#include
#include
main()
{
inti,r,j,k,l,p1,p2,fd[2];
charbuf[50],s[50];
pipe(fd);
while((p1=fork())==-1);
if(p1==0)
lockf(fd[1],1,0);
/*子进程1执行*/
/*管道写入端加锁*/
sprintf(buf,"ChildprocessP1issendingmessages!
\n");
printf("ChildprocessP1!
\n");
write(fd[1],buf,50);
lockf(fd[1],0,0);
/*信息写入管道*/
/*管道写入端解锁*/
sleep(5);
j=getpid();
k=getppid();
printf("P1%disweakup.MyparentprocessIDis%d.\n",j,k);
exit(0);
}
else
{while((p2=fork())==-1);
if(p2==0)
{
lockf(fd[1],1,0);
/*创建子进程2*/
/*子进程2执行*/
/*管道写入端加锁*/
sprintf(buf,"ChildprocessP2issendingmessages!
\n");
printf("ChildprocessP2!
\n");
write(fd[1],buf,50);
lockf(fd[1],0,0);
/*信息写入管道*/
/*管道写入端解锁*/
sleep(5);
j=getpid();
k=getppid();
printf("P2%disweakup.MyparentprocessIDis%d.\n",j,k);
exit(0);
}
else
{l=getpid();
wait(0);
if(r=read(fd[0],s,50)==-1)
printf("Can'treadpipe.\n");
else
printf("Parent%d:
%s\n",l,s);
wait(0);
if(r=read(fd[0],s,50)==-1)
printf("Can'treadpipe.\n");
else
printf("Parent%d:
%s\n",l,s);
exit(0);
}
}
}
}
运行结果:
思考:
(1)什么是管道?
进程如何利用它进行通信的?
解释一下实现方法。
(2)修改睡眠时机、睡眠长度,看看会有什么变化。
解释。
(3)加锁、解锁起什么作用?
不用它行吗?
答:
(1)管道是指能够连接一个写进程和一个读进程、并允许他们以生产者—消费者方式进行通信的一个共享文件,又称pipe文件。
由写进程从管道的入端将数据写入管道,而读进程则从管道的出端读出数据来进行通信。
(2)修改睡眠时机和睡眠长度都会引起进程被唤醒的时间不一,因为睡眠时机决定进程在何时睡眠,睡眠长度决定进程何时被唤醒。
(3)加锁、解锁是为了解决临界资源的共享问题。
不用它将会引起无法有效的管理数据,即数据会被修改导致读错了数据。
例程7:
软中断信号实验
#include
#include
main()
{
inti,j,k;
intfunc();
signal(18,func());
if(i=fork())
{
j=kill(i,18);
/*创建子进程*/
/*父进程执行*/
/*向子进程发送信号*/
printf("Parent:
signal18hasbeensenttochild%d,returned%d.\n",i,j);
k=wait();
/*父进程被唤醒*/
printf("Afterwait%d,Parent%d:
finished.\n",k,getpid());