操作系统实验指导书

二次信任 提交于 2019-12-06 07:57:43

《操作系统》实验教学大纲

一、基本信息

课程编码

350424005

课程学时

48

课程类别

学科基础课程

实验总学时

8

开出学期

5

开出单位

计算机系

适用专业

软件工程 网络工程

           

二、实验安排

序号

实 验 项 目

实验学时

每组人数

实验类型

开出要求

1

实验一  进程管理

2

1

验证

必做

实验二  进程通信

6

1

设计

必做

三、实验目的、内容与要求

实验一  进程管理

(一)实验目的

1.加深对进程概念的理解,明确进程和程序的区别。

2.进一步认识并发执行的实质。

3.分析进程竞争资源的现象,学习解决进程互斥与同步的方法。

(二)实验内容

1.Linux系统中进程的创建。

2.Linux系统中进程的控制。

(三)实验要求

1.掌握Linux系统中进程的创建、控制的实现方法。

2.根据实验内容,在Linux平台上用C语言编程实现,上机调试运行得出实验结果。

3.写出预习报告和实验报告。

实验二  进程通信

(一)实验目的

1.理解和掌握Linux系统中进程通信的基本原理。

2.进一步认识进程软中断通信、管道通信和消息队列通信的实质。

3.分析、设计进程软中断通信、管道通信和消息队列通信的实现方法。

4.掌握进程通信的实现机制。

(二)实验内容

1.设计进程的软中断通信。

2.设计进程的管道通信,实现父子进程的单机通信机制。

3. 设计进程的消息队列通信,实现客户机/服务器通信机制。

(三)实验要求

1.掌握进程软中断通信、管道通信和消息队列通信的设计与实现方法。

2.根据实验内容,在Linux平台上用C语言编程实现,上机调试运行得出实验结果;

3.写出预习报告和实验报告。

四、考核方式

实验成绩占课程总成绩的比重为20%。

考核方式根据实验课考勤、课前预习情况、课上实验能力、原型系统效果验收与实验报告的完成情况综合评分。

每个实验考核:实验预习占30%,实验能力和效果占30%,实验报告占40%。

五、建议教材与教学参考书

1.课程教材

[1] 张尧学. 计算机操作系统教程. 第四版. 北京:清华大学出版社. 2013.10

[2] 赵俊生.操作系统实验指导书.自编.2016

2.教学参考书

[1] 汤小丹.计算机操作系统.第三版.西安: 西安电子科技大学出版社.2008

[2] 徐虹. 操作系统实验指导. 北京: 清华大学出版社.2004

[3] 屠祁. 操作系统基础.第三版.北京: 清华大学出版社.2000

[4] 冯耀霖. 操作系统. 西安: 西安电子科技大学出版社.2001

[5] 左万历.计算机操作系统教程.第二版.北京:高等教育出版社.2004

六、编制说明

编制者:                       组长:马志强

执笔人:                       编制时间:2019年7月


实验一 进程管理

一、实验目的

1.学会在Linux中利用系统调用fork()创建进程。

2.加深对进程概念的理解,明确进程和程序的区别。

3.进一步认识在系统内进程并发执行的实质。

4.分析进程竞争资源的现象,学习解决进程互斥与同步的方法。

二、实验类型

    验证性实验。

三、实验预备知识

    1.阅读Linux的sched.h源码文件,加深对进程管理概念的理解。

    2.阅读Linux的fork.c源码文件,分析进程的创建过程。

四、实验内容

    1.进程的创建

    【任务】

    编写一段程序,使用系统调用fork()创建两个子进程,当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符;父进程显示字符“a”,子进程分别显示字符“b”和“c”。试观察记录屏幕上的显示结果,并分析原因。

【程序】

#include <stdio.h>

main()

{

   int p1,p2;

   while((p1=fork())= =-1);    /*创建子进程p1,失败时循环*/

   if(p1= =0)                /*子进程p1创建成功*/

      putchar(‘b’);

   else                     /*父进程返回*/

   {

      while((p2=fork())= =-1);  /*创建另一个子进程p2,失败时循环*/

      if(p2= =0)              /*子进程p2创建成功*/

         putchar(‘c’);

      else

         putchar(‘a’);         /*父进程执行*/

    }

}

 

    【执行结果】

    同学自己得到实验结果。

    【分析原因】

    同学自己分析多次执行产生不同实验结果的原因。

2.进程的控制

【任务】

修改已编写的程序,将每个进程的输出由单个字符改为一句话,再观察程序执行时屏幕上出现的现象,并分析其原因。如果在程序中使用系统调用lockf()来给每个进程加锁,可以实现进程之间的互斥,观察并分析出现的现象。

【程序1】

#include <stdio.h>

main()

{

       int p1,p2,i;

       while((p1=fork())= =-1);

       if(p1= =0)

          for(i=0;i<50;i++)

              printf(“child %d\n”,i);

       else

{

        while((p2=fork())= =-1)

        if(p2= =0)

            for(i=0;i<50;i++)

               printf(“son %d\n”,i);

        else

           for(i=0;i<50;i++)

               printf(“daughter %d\n”,i);

     }

}

【执行结果】

    同学自己得到实验结果。

    【分析原因】

同学自己分析多次执行产生不同实验结果的原因。

【程序2】

#include <stdio.h>

#include <unistd.h>

main()

{

  int p1,p2,i;

     while((p1=fork())= =-1);

  if(p1= =0)

{

       lockf(1,1,0);            /*加锁*/

         for(i=0;i<50;i++)

             printf(“child %d\n”,i);

         lockf(1,0,0);            /*解锁*/

  }

     else

{

      while((p2=fork())= =-1)

   if(p2= =0)

   {

          lockf(1,1,0);

          for(i=0;i<50;i++)

             printf(“son %d\n”,i);

          lockf(1,0,0);

      }

      else

      {

          lockf(1,1,0);

          for(i=0;i<50;i++)

             printf(“daughter %d\n”,i);

          lockf(1,0,0);

       }

     }

}

【执行结果】

    同学自己得到实验结果。

    【分析原因】

  同学自己分析多次执行产生不同实验结果的原因。

 

实验二 进程通信

一、实验目的

1.加深对各种进程通信基本工作原理的理解。

2.理解和掌握Linux系统中进程通信API的应用方法。

3.进一步认识进程软中断通信、管道通信和消息队列通信的实质。

4.分析、设计进程软中断通信的实现方法。

5.分析、设计进程的管道通信,实现父子进程的单机通信机制。

6.分析、设计进程的消息队列通信,实现客户机/服务器通信机制。

二、实验类型

       设计性实验。

三、实验预备知识

    1.阅读Linux进程通信技术(软中断、管道和消息队列)的使用方法。

    2.阅读Linux系统中单机和多机通信技术,掌握各种通信技术API的基本应用方法。

四、实验内容

1.进程的软中断通信

【举例1】

编制一段程序,使用系统调用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上来的中断信号(即按任意字母键和Enter键),当捕捉到中断信号后,父进程用系统调用kill()向两个子进程发出信号,子进程捕捉到信号后,分别输出下列信息后终止:

  child process 1 is killed by parent!

  child process 2 is killed by parent!

父进程等待两个子进程终止后,输出以下信息后终止:

parent process is killed!

【程序】

#include <sys/types.h>

#include <unistd.h>

#include <stdio.h>

#include <signal.h>

 

void waiting(),stop();

int wait_mark;

 

main()

{

    int p1,p2;

    while((p1=fork())= =-1);         /*创建进程p1*/

    if(p1>0)

        {

           while((p2=fork())= =-1);      /*创建进程p2*/

           if(p2>0)

{

   Printf(“parent run!\n”);

   Printf(“p1=%d\n”,p1);

   Printf(“p2=%d\n”,p2);

   wait_mark=1;

getchar(); 

kill(p1,16);               /*向p1发软中断信号16*/

kill(p2,17);               /*向p2发软中断信号17*/

sleep(5);                 /*父进程睡眠5秒*/

wait(0);                  /*等待子进程结束,同步*/

wait(0);                  /*等待另一子进程结束,同步*/

lockf(stdout,1,0);           /*标准输出加锁*/

printf(“parent process is killed!\n”);

lockf(stdout,0,0);           /*标准输出解锁*/

exit(0);                   /*父进程终止*/

}

           else

           {

              printf(“p2 run!\n”);

   wait_mark=1;

signal(17,stop);       /*接收父进程发来的软中断信号17,并转stop*/

waiting();

lockf(stdout,1,0);      /*标准输出加锁*/

printf(“child process 2 is killed by parent!\n”);

lockf(stdout,0,0);      /*标准输出解锁*/

exit(0);              /*子进程p2终止*/

            }

          }

          else

          {

              printf(“p1 run!\n”);

   wait_mark=1;

signal(16,stop);       /*接收父进程发来的软中断信号16,并转stop*/

waiting();

lockf(stdout,1,0);      /*标准输出加锁*/

printf(“child process 1 is killed by parent!\n”);

lockf(stdout,0,0);      /*标准输出解锁*/

exit(0);              /*子进程p1终止*/

           }

        }

        void waiting()

        {

           printf(“waiting begin!\n”);

           while(wait_mark!=0);

           printf(“waiting end!\n”);

        }

        void stop()

        {

           wait_mark=0;

           printf(“signal stop!”);

        }

【执行结果】

    同学自己得到实验结果。

    【分析原因】

    同学自己分析产生该实验结果的原因。

    【举例2】

    在上面任务1中,增加语句signal(SIGINT,SIG_IGN)和语句signal(SIGQUIT,SIG_IGN),观察执行结果,并分析原因。这里signal(SIGINT,SIG_IGN)和signal(SIGQUIT,SIG_IGN)分别为忽略“Ctrl+c”键信号以及忽略中断信号。

    【程序】

#include <sys/types.h>

#include <unistd.h>

#include <stdio.h>

#include <signal.h>

   

    int pid1,pid2;

    int endflag=0,pf1=0,pf2=0;

   

    void intdelete()

    {

       kill(pid1,16);

       kill(pid2,17);

       endflag=1;

    }

    void int1()

    {

       printf(“child process 1 is killed by parent!”);

       exit(0);

    }

    void int2()

    {

       printf(“child process 2 is killed by parent!”);

       exit(0);

    }

 

    main()

    {

       int exitpid;

       signal(SIGINT,SIG_IGN);

       signal(SIGQUIT,SIG_IGN);

       while((pid1=fork())= =-1);

       if(pid1= =0)

       {

          printf(“process 1 run!\n”);

          signal(SIGUSR1,int1);

          signal(16, SIG_IGN);

          pause();

          exit(0);

       }

       else

       {

          while((pid2=fork())= =-1);

          if(pid2= =0)

          {

             printf(“process 2 run!\n”);

             signal(SIGUSR2,int2);

             signal(17, SIG_IGN);

             pause();

             exit(0);

          }

          else

          {

             printf(“parent run!\n”);

             signal(SIGINT,intdelete);

             waitpid(-1,&exitpid,0);

             printf(“parent process is killed!\n”);

             exit(0);

           }

         }

       }

【执行结果】

    同学自己得到实验结果。

    【分析原因】

    同学自己分析产生该实验结果的原因。

2.进程的管道通信

【举例】

 编制一段程序,实现进程的管道通信。使用系统调用pipe()建立一条管道线。两个子进程p1和p2分别向管道各写一句话:

 child 1 is sending a message!

 child 2 is sending a message!

 而父进程则从管道中读出来自于两个子进程的信息,显示在屏幕上。

 【程序】

#include <unistd.h>

#include <stdio.h>

#include <signal.h>

   

    int pid1,pid2;

 

 main()

 {

     int fd[3];

     char outpipe[100],inpipe[100];

     pipe(fd);

     while((pid1=fork())= =-1);

     if(pid1= =0)

     {

        printf(“p1 run!\n”);

        lockf(fd[1],1,0);

        sprintf(outpipe,”child 1 process is sending a message!”);

        write(fd[1],outpipe,50);

        sleep(1);

        lockf(fd[1],0,0);

        exit(0);

      }

      else

{

         while((pid2=fork())= =-1);

         if(pid2= =0)

         {

             printf(“p2 run!\n”);

             lockf(fd[1],1,0);

             sprintf(outpipe,”child 2 process is sending a message!”);

             write(fd[1],outpipe,50);

             sleep(1);

             lockf(fd[1],0,0);

             exit(0);

    }

    else

    {

       printf(“parent run!\n”);

       wait(0);

       read(fd[0],inpipe,50);

       printf(“%s\n”,inpipe);

       wait(0);

       read(fd[0],inpipe,50);

       printf(“%s\n”,inpipe);

       exit(0);

     }

   }

}

【执行结果】

    同学自己得到实验结果。

    【分析原因】

    同学自己分析产生该实验结果的原因。

3.进程的消息队列通信

实验要求:

       (1)实现客户机与服务器之间的通信程序。

              1)基本要求:实现1台客户机对1台服务器;提高要求:实现n台客户机对1台服务器;

              2)要求服务器分别接收客户机数据。

              3)要求每个客户机与服务器采用消息队列通信机制来发送和接收消息。

       (2)测试程序,给出测试结果并进行分析。

       (3)书写预习报告和实验报告。

实验提示:

       进程间消息队列通信主要用到的四个系统调用如下:

int  msgget(key_t key,int msgflg)

int  msgctl(int msgqid,int cmd,struct msqid_ds *buf)

int  msgsnd(int msgqid,struct msgbuf  *msgp, size_t msgsz,int msgflg)

int  msgrcv(int msgqid,struct msgbuf  *msgp, size_t msgsz,long msgtyp,int msgflg)

包含的头文件如下:

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

【举例】

 编制一个客户机进程,定义消息的格式,使用msgget()系统调用创建消息队列,使用msgsnd()和msgrcv()系统调用实现与服务进程之间消息的发送和接收,通信结束后使用msgctl()系统调用删除相关的消息队列。

(1)客户机程序设计

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

#define MSGKEY  75

struct msgform{

 long mtype;

char mtext[256];

};

main(){

struct msgform msg;

int msgqid,pid,*pint;

msgqid=msgget(MSGKEY,0777);

pid=getpid();

pint=(int *)msg.mtext;

*pint=pid;

msg.mtype=1;

msgsnd(msgqid,&msg,sizeof(int),0);

msgrcv(msgqid,&msg,256,pid,0);

printf(“client:receive from pid%d\n”,*pint);

}

(2)服务器程序设计

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

#define MSGKEY  75

struct msgform{

         long mtype;

         char mtext[256];

      }msg;

int msgqid;

main(){

    int i,pid,*pint;

    extern cleanup();

    for(i=0;i<20;i++)

       signal(i,cleanup);

    msqid=msgget(MSGKEY,0777|IPC_CREAT);

    for(;;){

        msgrcv(msgqid,&msg,256,1,0);

        pint=(int *)msg.mtext;

        *pint=pid;

        printf(“server:receive from pid%d\n”,*pint);

        msg.mtype=pid;

        *pint=getpid();

        msgsnd(msgqid,&msg,sizeof(int),0);

        }

}

void cleanup()

{

       msgctl(msgqid,IPC_RMID,0);

       exit();

}

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!