作业实验13DOC.docx
《作业实验13DOC.docx》由会员分享,可在线阅读,更多相关《作业实验13DOC.docx(15页珍藏版)》请在冰豆网上搜索。
作业实验13DOC
操作系统实验1~3理学院信息与计算科学1303许艳红学号2013310200724
实验1
1建立两个子进程
#include
main()
{
intchildpid1,childpid2;
while((childpid1=fork())==-1);
if(childpid1==0)
putchar('b');
else
{
while((childpid2=fork())==-1);
if(childpid2==0)
putchar('c');
else
putchar('a');
}
}
运行结果acb,bca,bac等,因为fork()创建进程的时间多于输出一个字符的时间,所以当创建进程2时,进程1一输出‘b',又进程2和主程序输出字符的次序具有随机性,所以会出现多种情况。
2.输出一句话
#include
intmain()
{
intpid;
pid=fork();
if(pid==0)
printf("Iamson,mypidis%d.\n",getpid());
elseif(pid>0)
{
printf("I'mfather,mypidis%d.\n",getpid());
pid=fork();
if(pid==0)
printf("I'mdaughterprocess,mypidis%d.\n",getpid());
elseif(pid>0)
printf("I'mfatherprocess,mypidis%d.\n",getpid());
else
printf("fork()error.\n");
}
elseprintf("fork()error.\n");
}
因为输出函数printf()输出字符时不会中断,所以输出的每句话就相当于一个字符,最终也会有多种情况。
进程加锁
#include
intmain()
{
intpid;
pid=fork();
if(pid==0)
printf("Iamson,mypidis%d.\n",getpid());
lockf(1,0,0);
elseif(pid>0)
{
/*从子进程1返回到父进程时,再创建子进程2。
*/
printf("I'mfather,mypidis%d.\n",getpid());
pid=fork();
if(pid==0)
lockf(1,0,0);
printf("I'mdaughterprocess,mypidis%d.\n",getpid());
elseif(pid>0)
lockf(1,0,0);
printf("I'mfatherprocess,mypidis%d.\n",getpid());
else
printf("fork()error.\n");
}
elseprintf("fork()error.\n");
}
与未上锁时输出的结果大致相同,这是因为不同进程之间不存在共享临界资源(其中打印机的互斥性已由操作系统保证)问题,所以加锁与不加锁效果相同。
3.软中断通信
#include
#include
#include
#include
#include
#include
#include
#include
voidgo();
voidstop1(),stop2();
pid_tp1,p2;
voidmain()
{
intstatus=-1;
intrtv;
while((p1=fork())==-1);/*创建子进程p1*/
if(p1>0)
{
while((p2=fork())==-1);/*创建子进程p2*/
if(p2>0)
{
printf("Parentprocess%d\n",getpid());
signal(SIGINT,go);/*接收到信号,转go*/
pause();
sleep
(2);
wait(NULL);
wait(NULL);
printf("Parentprocessiskilled!
\n");
exit(0);
}
else
{
printf("Process2,pid%d\n",getpid());
signal(SIGINT,SIG_IGN);pre">signal(SIGUSR2,stop2);
if(signal(SIGUSR2,stop2)==SIG_ERR){
printf("Can'tcatchSIGUR2");
}
pause();
printf("Process2End\n");
}
}
else
{
printf("Process1,pid%d\n",getpid());
signal(SIGINT,SIG_IGN);pre">-webkit-auto;"if(signal(SIGUSR1,stop1)==SIG_ERR){
printf("Can'tcatchSIGUR2");
}
pause();
printf("Process1End\n");
}
printf("childexitstatusis%d\n",WEXITSTATUS(status));
}
voidgo()
{
intrtv;
printf("Funcgo\n");
rtv=kill(p1,SIGUSR1);/*向p1发软中断信号16*/
if(rtv){
printf("failtosendsignal16top1\n");
}else{
printf("Succedinsendingsignal16top1\n");
}
rtv=kill(p2,SIGUSR2);/*向p2发软中断信号17*/
if(rtv){
printf("failtosendsignal17top2\n");
}else{
printf("Succedinsendingsignal17top2\n");
}
}
voidstop2()
{
printf("Childprocess2iskilledbyparent!
\n");
exit(0);
}
voidstop1()
{
printf("Childprocess1iskilledbyparent!
\n");
exit(0);
}
Wait(0)用来实现父子进程的同步;因为进程从父进程中继承了Del信号,及其默认的处理程序,在子进程中并没有屏蔽Del信号,因此,当输入信号时,子进程会处理父进程为其指定的信号之前,调用默认的处理Del信号的程序,直接退出。
所以应该在子进程中屏蔽掉系统默认的对Del信号的处理
4进程的管道通信
#include
#include
#include
#include"stdlib.h"
intpid1,pid2;
main()
{
intfd[2];
charoutpipe[100],inpipe[100];
pipe(fd);
while((pid1=fork())==-1);
if(pid1==0)
{
printf("p1\n");
lockf(fd[1],1,0);
sprintf(outpipe,"child1processissendingmessage!
");
write(fd[1],outpipe,50);
sleep(5);
lockf(fd[1],0,0);
exit(0);
}
else
{
while((pid2=fork())==-1);
if(pid2==0)
{
lockf(fd[1],1,0);
sprintf(outpipe,"child2processissendingmessage!
");
write(fd[1],outpipe,50);
sleep(5);
lockf(fd[1],0,0);
exit(0);
}
else
{
wait(0);
read(fd[0],inpipe,50);
printf("%s\n",inpipe);
wait(0);
read(fd[0],inpipe,50);
printf("%s\n",inpipe);
exit(0);
}
}
}
管道通过lockf(),而lockf(fd[1],1,0)实现进程间的互斥,用write()写入管道,用read()读取管道内容,通过延迟一段时间,sleep(),子进程完成写入人物,由于管道中的延迟问题,否则在未完成写人物时,父进程调用读任务则出错
实验2
1消息的接受和发送
server建立一个key为75的消息队列,等待其它进程发来的消息。
当遇到类型为1的消息,则作为结束信号,取消该队列,并退出server。
server每接收到一个消息后显示一句“(server)received”。
client使用key为75的消息队列,先后发送类型从10到1的消息,然后退出。
最后一个消息,即是server端需要的结束信号。
client每发送一条消息后显示一句“(client)sent”
server.c参考程序如下:
#include
#include
#include
#include
#include
#defineMSGKEY75
structmsgform
{
longmtype;
charmtext[1000];
}msg;
intmsgqid;
voidserver()
{
msgqid=msgget(MSGKEY,0777|IPC_CREAT);/*创建75#消息队列*/
do
{
msgrcv(msgqid,&msg,1030,0,0);/*接收消息*/
printf("(server)received\n");
}while(msg.mtype!
=1);
msgctl(msgqid,IPC_RMID,0);/*删除消息队列,归还资源*/
exit(0);
}
main()
{
server();
}
client.c参考程序如下:
#include
#include
#include
#include
#include
#defineMSGKEY75
structmsgform
{
longmtype;
charmtext[1000];
}msg;
intmsgqid;
voidclient()
{
inti;
msgqid=msgget(MSGKEY,0777);/*打开75#消息队列*/
for(i=10;i>=1;i--)
{
msg.mtype=i;
printf("(client)sent\n");
msgsnd(msgqid,&msg,1024,0);/*发送消息*/
}
exit(0);
}
main()
{
client();
}
message的传送和控制并不能保证完全同步,当一个程序不在激活状态的时候,它完全可能继续睡眠,造成了上面的现象,在多次发送消息后才接收消息。
2.共享存储区的创建、附接和断接
#include
#include
#include
#defineSHMKEY75
intshmid,i,p1,p2;
int*addr;
voidCLIENT()/*发送过程*/
{
inti;
shmid=shmget(SHMKEY,1024,0777);/*打开共享存储区*/
addr=(int*)shmat(shmid,0,0);/*获取共享存储区的首地址*/
for(i=29;i>=0;i--)
{
while(*addr!
=-1);/*判断是否可写*/
*addr=i;/*写数据*/
printf("%d",*addr);
printf("(client)sent\n");
}
exit(0);
}
voidSERVER()/*接收进程*/
{
inti;
shmid=shmget(SHMKEY,1024,0777|IPC_CREAT);/*创建共享存储区*/
addr=(int*)shmat(shmid,0,0);
do
{
*addr=-1;
while(*addr==-1);/*判断信息是否传来*/
printf("%d",*addr+30);/*读,并加工数据*/
printf("(server)received\n");
}while(*addr);
shmctl(shmid,IPC_RMID,0);/*撤消共享存储区,归还资源*/
exit(0);
}
main()
{
while((p1=fork())==-1);/*父进程*/
if(p1==0)SERVER();/*子进程p1*/
while((p2=fork())==-1);/*父进程*/
if(p2==0)CLIENT();/*子进程p2*/
wait(0);/*父进程*/
wait(0);/*父进程*/
}
用主程序作为“引子”,先后fork()两个子进程,SERVER和CLIENT,让它们利用共享存储区的方式进行通信:
CLIENT端获取一个KEY为75的共享区,当共享区第一个字节的值为-1时,表示SERVER端空闲。
这时CLIENT向共享区中填入要发送的数据,同时显示自己发送的数据,然后显示一句“(client)sent”。
SERVER端获取(如果还没有就创建)一个KEY为75的共享存储区,并将第一个字节置为-1,作为数据空的标志,等待其他进程发来的消息。
当该字节的值发生变化时,表示收到了信息,SERVER取得该数据,进行处理,然后将处理结果显示出来,再显示一句“(server)received”。
发送和接收的过程循环进行30次。
父进程在SERVER和CLIENT均退出后结束。
实验三
#include
#include
#include
#defineTRUE1
#defineFALSE0
#defineINVALID-1
#defineNULL0
#definetotal_instruction320/*指令流长*/
#definetotal_vp32/*虚页长*/
#defineclear_period50/*清零周期*/
typedefstruct{/*页面结构*/
intpn,pfn,counter,time;
}pl_type;
pl_typepl[total_vp];/*页面结构数组*/
structpfc_struct{/*页面控制结构*/
intpn,pfn;
structpfc_struct*next;
};
structpfc_structpfc[total_vp],*freepf_head,*busypf_head,*busypf_tail;
intdiseffect,a[total_instruction];
intpage[total_instruction],offset[total_instruction];
voidinitialize();
voidFIFO();
voidLRU();
voidOPT();
voidLFU();
voidCLOCK();
voidNRU();
intmain()
{
intS,i;
srand(10*getpid());
S=(int)(319.0*rand()/RAND_MAX)+1;
for(i=0;ia[i]=S;a[i+1]=a[i]+1;
a[i+2]=(int)(1.0*a[i]*rand()/RAND_MAX);a[i+3]=a[i+2]+1;S=(int)(1.0*rand()*(318-a[i+2])/RAND_MAX)+a[i+2]+2;
}
for(i=0;ipage[i]=a[i]/10;
offset[i]=a[i]%10;
}
for(i=4;i<=32;i++){
printf("%2dpageframes\t",i);
FIFO(i);
LRU(i);
NRU(i);
OPT(i);
SCR(i);
CLOCK(i);
}
return0;
}
voidinitialize(inttotal_pf)
{
inti;
diseffect=0;
for(i=0;i{
pl[i].pn=i;
pl[i].pfn=INVALID;pl[i].counter=0;
pl[i].time=-1;}
for(i=1;i{
pfc[i-1].next=&pfc[i];
pfc[i-1].pfn=i-1;
}
pfc[total_pf-1].next=NULL;
pfc[total_pf-1].pfn=total_pf-1;
freepf_head=&pfc[0];
}
voidFIFO(inttotal_pf)
{
inti;
structpfc_struct*p;
initialize(total_pf);
busypf_head=busypf_tail=NULL;
for(i=0;i{
if(pl[page[i]].pfn==INVALID){
diseffect+=1;
if(freepf_head==NULL)
{
p=busypf_head->next;
pl[busypf_head->pn].pfn=INVALID;
freepf_head=busypf_head;
freepf_head->next=NULL;
busypf_head=p;
}
p=freepf_head->next;,
freepf_head->next=NULL;
freepf_head->pn=page[i];
pl[page[i]].pfn=freepf_head->pfn;
if(busypf_tail==NULL)busypf_head=busypf_tail=freepf_head;
else
{
busypf_tail->next=freepf_head;
busypf_tail=freepf_head;
}
freepf_head=p;
}
}
printf("FIFO:
%6.4f",1-(float)diseffect/320);
}
我在这里只定义了initialize()函数和FIFO()算法,因为只充分了解FIFO()算法,即顺序写入数据,顺序读出数据,是一种先进先出的数据缓存。
又了解到虚拟存储器的优缺点,即不用存储器,直接调出来就好,但其容量太小。
与其他算法相比,这种算法的命中率最低。
另外,随机数的产生可以用函数srand(),rand()