理发师问题操作系统_操作系统理发师问题 - CSDN
  • http://learn.bitsde.com/hep/os/chapter2/section3/2.3.3.htm 这是我在网上找到的最详实,最严谨的资料了,贴在下面和大家分享哦,O(∩_∩)O~ 参考网站http://222.

    http://learn.bitsde.com/hep/os/chapter2/section3/2.3.3.htm
    这是我在网上找到的最详实,最严谨的资料了,贴在下面和大家分享哦,O(∩_∩)O~

     

    参考网站http://222.22.224.75/czxt/chapter2/section3/2.3.3.htm

                                     2.3.3 理发师睡觉问题

    理发店里有一位理发师、一把理发椅和n把供等候理发的顾客坐的椅子。如果没有顾客,则理发师便在理发椅上睡觉,如图2-20所示。当一个顾客到来时,他必须先叫醒理发师,如果理发师正在理发时又有顾客来到,则如果有空椅子可坐,他们就坐下来等。如果没有空椅子,他就离开。这里的问题是为理发师和顾客各编写一段程序来描述他们的行为,要求不能带有竞争条件。

    图 2-20.gif (7360 bytes)

    图2-20 睡觉的理发师

    我们的解法使用三个信号量:customers,用来记录等候理发的顾客数(不包括正在理发的顾客);barbers,记录正在等候顾客的理发师数,为0或1;mutex,用于互斥。我们还需要一个变量waiting,它也用于记录等候的顾客数,实际上是customers的一份拷贝。之所以使用waiting是因为无法读取信号量的当前值。在该解法中,进入理发店的顾客必须先看等候的顾客数,如果少于椅子数,他留下来等,否则他就离开。

    我们的解法示于图2-21。

    	# define CHAIRS 5 /*为等待的顾客准备的椅子数*/
    
    	typedef int semaphone ; /*运用你的想象力*/
    	semaphore customers=0; /*等待服务的顾客数*/
    	semaphore barbers=0; /*等待顾客的理发师数*/
    	semaphore mutex=1; /*用于互斥*/
    	int waiting=0; /*等待的顾客(还没理发的)*/
    
    	void barber(void)
    	{
    		while(TRUE)
    		{
    			down(customers); 
    			/*如果顾客数是0,则睡眠*/
    			down(mutex); /*要求进程等待*/
    			waiting=waiting-1; /*等待顾客数减1*/
    			up(barbers); 
    			/*一个理发师现在开始理发了*/
    			up(mutex); /*释放等待*/
    			cut_hair(); /*理发(非临界区操作)*/
    		}
    	}
    
        void customers(void)
       {
           down(mutex);/*进入临界区*/
           if(waiting < CHAIRS)
           {/*如果没有空椅子,就离开*/
              waiting = waiting + 1;/*等待顾客数加1*/
              up(customers);  /*如果必要的话,唤醒理发师*/
              up(mutex); /*释放访问等待*/
              down(barbers);/*如果barbers为0,就入睡*/
              get_haircut();/*坐下等待服务*/
            }
            else
               up(mutex);/*店里人满了,走吧*/
        }
           

     

    图2-21 理发师问题的一种解法

    展开全文
  • 操作系统上机5:理发问题

    万次阅读 2019-03-18 18:54:07
    理发店问题:假设理发店的理发室中有 3 个理发椅子和 3 个理发师,有一个可容 纳4个顾客坐等理发的沙发。此外还有一间等候室,可容纳13位顾客等候进入理发 室。顾客如果发现理发店中顾客已满(超过 20 人),就不...

    理发店问题:假设理发店的理发室中有 3 个理发椅子和 3 个理发师,有一个可容 纳4个顾客坐等理发的沙发。此外还有一间等候室,可容纳13位顾客等候进入理发 室。顾客如果发现理发店中顾客已满(超过 20 人),就不进入理发店。 在理发店内,理发师一旦有空就为坐在沙发上等待时间最长的顾客理发,同时 空出的沙发让在等候室中等待时间最长的的顾客就坐。顾客理完发后,可向任何一 位理发师付款。但理发店只有一本现金登记册,在任一时刻只能记录一个顾客的付 款。理发师在没有顾客的时候就坐在理发椅子上睡眠。理发师的时间就用在理发、 收款、睡眠上。


    ①建立ipc.h 写入代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/sem.h>
    #include <sys/msg.h>
    
    #define BUFSZ   256
    #define MAXVAL   100
    #define STRSIZ   8
    #define WRITERQUEST  1 //写请求标识
    #define READERQUEST  2 //读请求标识
    #define FINISHED  3 //读写完成标识
    
    /*信号灯控制用的共同体*/
    typedef union semuns {
        int val;
        } Sem_uns;
    
    /* 消息结构体*/
    typedef struct msgbuf {
        long mtype;
        int  mid;
        } Msg_buf;
    
    
    //信号量
    key_t costomer_key;
    int costomer_sem;
    key_t account_key;
    int account_sem;
    
    int sem_val;
    int sem_flg;
    
    //消息队列
    int wait_quest_flg;
    key_t wait_quest_key;
    int wait_quest_id;
    int wait_respond_flg;
    key_t wait_respond_key;
    int wait_respond_id;
    
    int sofa_quest_flg;
    key_t sofa_quest_key;
    int sofa_quest_id;
    int sofa_respond_flg;
    key_t sofa_respond_key;
    int sofa_respond_id;
    
    int get_ipc_id(char *proc_file,key_t key);
    char *set_shm(key_t shm_key,int shm_num,int shm_flag);
    int set_msq(key_t msq_key,int msq_flag);
    int set_sem(key_t sem_key,int sem_val,int sem_flag);
    int down(int sem_id);
    int up(int sem_id);
    
    

    ②建立ipc.c 写入代码

     #include "ipc.h"
    
    int get_ipc_id(char *proc_file,key_t key) {
        FILE *pf;
        int i,j;
        char line[BUFSZ],colum[BUFSZ];
        if((pf = fopen(proc_file,"r")) == NULL){
            perror("Proc file not open");
            exit(EXIT_FAILURE);
        }
        fgets(line, BUFSZ,pf);
        while(!feof(pf)){
            i = j = 0;
            fgets(line, BUFSZ,pf);
            while(line[i] == ' ') i++;
            while(line[i] !=' ')
                colum[j++] = line[i++];
                colum[j] = '\0';
            if(atoi(colum) != key)
                continue;
            j=0;
            while(line[i] == ' ')
                i++;
            while(line[i] !=' ')
                colum[j++] = line[i++];
            colum[j] = '\0';
            i = atoi(colum);
            fclose(pf);
            return i;
        }
        fclose(pf);
        return -1;
    }
    int down(int sem_id) {
        struct sembuf buf;
        buf.sem_op = -1;
        buf.sem_num = 0;
        buf.sem_flg = SEM_UNDO;
        if((semop(sem_id,&buf,1)) <0) {
            perror("down error ");
            exit(EXIT_FAILURE);
        }
        return EXIT_SUCCESS;
    }
    
    int up(int sem_id) {
        struct sembuf buf;
        buf.sem_op = 1;
        buf.sem_num = 0;
        buf.sem_flg = SEM_UNDO;
        if((semop(sem_id,&buf,1)) <0) {
            perror("up error ");
            exit(EXIT_FAILURE);
        }
        return EXIT_SUCCESS;
    }
    
    int set_sem(key_t sem_key,int sem_val,int sem_flg) {
        int sem_id;  Sem_uns sem_arg;
    
        //测试由 sem_key 标识的信号灯数组是否已经建立
        if((sem_id = get_ipc_id("/proc/sysvipc/sem",sem_key)) < 0 ){
            //semget 新建一个信号灯,其标号返回到 sem_id
            if((sem_id = semget(sem_key,1,sem_flg)) < 0){
                perror("semaphore create error");
                exit(EXIT_FAILURE);
            }
            //设置信号灯的初值
            sem_arg.val = sem_val;
            if(semctl(sem_id,0,SETVAL,sem_arg) <0){
                perror("semaphore set error");
                exit(EXIT_FAILURE);
            }
        }
       return sem_id;
    }
    
    char * set_shm(key_t shm_key,int shm_num,int shm_flg) {
        int i,shm_id;
        char * shm_buf;
    
        //测试由 shm_key 标识的共享内存区是否已经建立
        if((shm_id = get_ipc_id("/proc/sysvipc/shm",shm_key)) < 0 ){
            //shmget 新建 一个长度为 shm_num 字节的共享内存,其标号返回到 shm_id
            if((shm_id = shmget(shm_key,shm_num,shm_flg)) <0){
                perror("shareMemory set error");
            exit(EXIT_FAILURE);
        }
        //shmat 将由 shm_id 标识的共享内存附加给指针 shm_buf
        if((shm_buf = (char *)shmat(shm_id,0,0)) < (char *)0){
            perror("get shareMemory error");
            exit(EXIT_FAILURE);
        }
        for(i=0; i<shm_num; i++) shm_buf[i] = 0;
            //初始为 0
        }
        //shm_key 标识的共享内存区已经建立,将由 shm_id 标识的共享内存附加给指 针 shm_buf
        if((shm_buf = (char *)shmat(shm_id,0,0)) < (char *)0){
            perror("get shareMemory error");
            exit(EXIT_FAILURE);
        }
    return shm_buf;
    }
    
    int set_msq(key_t msq_key,int msq_flg){
        int msq_id;
        //测试由 msq_key 标识的消息队列是否已经建立
        if((msq_id = get_ipc_id("/proc/sysvipc/msg",msq_key)) < 0 ){
                //msgget 新建一个消息队列,其标号返回到 msq_id
            if((msq_id = msgget(msq_key,msq_flg)) < 0){
                perror("messageQueue set error");
            exit(EXIT_FAILURE);
            }
        }
        return msq_id;
    }
    
    

    ③建立Customer.c

    #include "ipc.h"
    int main(int argc,char *argv[])
    {
        int rate;
        Msg_buf msg_arg;
        //可在在命令行第一参数指定一个进程睡眠秒数,以调解进程执行速度
        if(argv[1] != NULL) rate = atoi(argv[1]);
        else rate = 3;
    
        //联系一个请求消息队列
        wait_quest_flg = IPC_CREAT| 0644;
        wait_quest_key = 101;
        wait_quest_id = set_msq(wait_quest_key,wait_quest_flg);
        //联系一个响应消息队列
        wait_respond_flg = IPC_CREAT| 0644;
        wait_respond_key = 102;
        wait_respond_id = set_msq(wait_respond_key,wait_respond_flg);
    
        //联系一个请求消息队列
        sofa_quest_flg = IPC_CREAT| 0644;
        sofa_quest_key = 201;
        sofa_quest_id = set_msq(sofa_quest_key,sofa_quest_flg);
        //联系一个响应消息队列
        sofa_respond_flg = IPC_CREAT| 0644;
        sofa_respond_key = 202;
        sofa_respond_id = set_msq(sofa_respond_key,sofa_respond_flg);
    
        //信号量使用的变量
        costomer_key = 301;//顾客同步信号灯键值
        account_key = 302;//账簿互斥信号灯键值
        sem_flg = IPC_CREAT | 0644;
        //顾客同步信号灯初值设为0
        sem_val = 0;
        //获取顾客同步信号灯,引用标识存 costomer_sem
        costomer_sem = set_sem(costomer_key,sem_val,sem_flg);
        //账簿互斥信号灯初值设为 1
        sem_val = 1;
        //获取消费者同步信号灯,引用标识存 cons_sem
        account_sem = set_sem(account_key,sem_val,sem_flg);
    
        int sofa_count=0;
        int wait_count=0;
        int i=0;
     //   int count=0;
        while(1) {
            sleep(rate);
        //    count++;
        //    printf("count = %d ", count);
            i++;
         //   printf("i = %d ", i);
            msg_arg.mid = i;
            if(sofa_count < 4) {
                if(wait_count != 0) {
                    i--;
                    //阻塞方式接收消息
                    msgrcv(wait_quest_id, &msg_arg, sizeof(msg_arg), 0, 0);
                     printf("mid = %d ", msg_arg.mid);
                    msgsnd(wait_respond_id, &msg_arg,sizeof(msg_arg), 0);
                    printf("%d customer from waiting room to sofa\n", msg_arg.mid);
                 //   up(costomer_sem);
                } else {
                    printf("%d new customer sit sofa\n", i);
                }
    
                sofa_quest_flg=IPC_NOWAIT;
                if(msgsnd(sofa_quest_id, &msg_arg, sizeof(msg_arg), sofa_quest_flg) >= 0){
                  //  sofa_count++;
                 //  return 0;
                }
                sofa_count++;
    
            } else if(wait_count < 13) {
                printf("sofa is full %d customer is waiting in the waiting room\n", i);
                wait_quest_flg = IPC_NOWAIT;
                msgsnd(wait_quest_id, &msg_arg, sizeof(msg_arg), wait_quest_flg);
                wait_count++;
    
            } else {
                printf("waiting room is full %d customer can't get into barber shop\n", i);
             //   down(costomer_sem);
                  msgrcv(sofa_respond_id, &msg_arg, sizeof(msg_arg), 0, 0);
                  sofa_count--;
                  i--;
            }
            sofa_quest_flg=IPC_NOWAIT;
            if(msgrcv(sofa_respond_id, &msg_arg, sizeof(msg_arg), 0, sofa_quest_flg)>=0){
                sofa_count--;
            }
            wait_quest_flg = IPC_NOWAIT;
            if(msgrcv(wait_respond_id, &msg_arg, sizeof(msg_arg), 0, wait_quest_flg)>=0) {
                wait_count--;
            }
        }
    
        return 0;
    }
    
    

    ④建立Barber.c

    #include "ipc.h"
    int main(int argc,char *argv[])
    {
      //  int i;
        int rate;
        Msg_buf msg_arg;
        //可在在命令行第一参数指定一个进程睡眠秒数,以调解进程执行速度
        if(argv[1] != NULL) rate = atoi(argv[1]);
        else rate = 3;
    
        //联系一个请求消息队列
        wait_quest_flg = IPC_CREAT| 0644;
        wait_quest_key = 101;
        wait_quest_id = set_msq(wait_quest_key,wait_quest_flg);
        //联系一个响应消息队列
        wait_respond_flg = IPC_CREAT| 0644;
        wait_respond_key = 102;
        wait_respond_id = set_msq(wait_respond_key,wait_respond_flg);
    
        //联系一个请求消息队列
        sofa_quest_flg = IPC_CREAT| 0644;
        sofa_quest_key = 201;
        sofa_quest_id = set_msq(sofa_quest_key,sofa_quest_flg);
        //联系一个响应消息队列
        sofa_respond_flg = IPC_CREAT| 0644;
        sofa_respond_key = 202;
        sofa_respond_id = set_msq(sofa_respond_key,sofa_respond_flg);
    
        //信号量使用的变量
        costomer_key = 301;//顾客同步信号灯键值
        account_key = 302;//账簿互斥信号灯键值
        sem_flg = IPC_CREAT | 0644;
        //顾客同步信号灯初值设为0
        sem_val = 0;
        //获取顾客同步信号灯,引用标识存 costomer_sem
        costomer_sem = set_sem(costomer_key,sem_val,sem_flg);
        //账簿互斥信号灯初值设为 1
        sem_val = 1;
        //获取消费者同步信号灯,引用标识存 cons_sem
        account_sem = set_sem(account_key,sem_val,sem_flg);
    
        int pid1, pid2;
        pid1=fork();
        if(pid1==0) {
            while(1) {
               //  wait_quest_flg=IPC_NOWAIT;
                //printf("%d barber is sleeping \n", getpid());
                wait_quest_flg=IPC_NOWAIT;
    	    sleep(rate);
    	    
                if(msgrcv(sofa_quest_id, &msg_arg, sizeof(msg_arg), 0, wait_quest_flg)>=0) {
    		//printf("temp %d\n",temp);
                    msgsnd(sofa_respond_id, &msg_arg,sizeof(msg_arg), 0);
                    printf("%d barber is serving for %d customer \n", getpid(), msg_arg.mid);
                    
                    down(account_sem);
                    printf("%d barber is collect %d customer's money\n", getpid(), msg_arg.mid);
                    up(account_sem);
                }else {
                        printf("%d barber is sleeping\n", getpid());
    
                }
            }
        } else {
            pid2=fork();
            if(pid2==0) {
                while(1) {
                   //  wait_quest_flg=IPC_NOWAIT;
                   //printf("%d barber is sleeping\n", getpid());
                   wait_quest_flg=IPC_NOWAIT;
    		sleep(rate);
                   if(msgrcv(sofa_quest_id, &msg_arg, sizeof(msg_arg), 0, wait_quest_flg)>=0) {
                        msgsnd(sofa_respond_id, &msg_arg,sizeof(msg_arg), 0);
                        printf("%d barber is serving for %d customer \n", getpid(), msg_arg.mid);
                        
                        down(account_sem);
                        printf("%d barber is collect %d customer's money\n", getpid(), msg_arg.mid);
                        up(account_sem);
                   } else {
                        printf("%d barber is sleeping\n", getpid());
    
                   }
                }
            } else {
                 while(1) {
                 //  wait_quest_flg=IPC_NOWAIT;
                   //printf("%d barber is sleeping\n", getpid());
                   wait_quest_flg=IPC_NOWAIT;
    		sleep(rate);
                   if(msgrcv(sofa_quest_id, &msg_arg, sizeof(msg_arg), 0, wait_quest_flg)>=0) {
                        msgsnd(sofa_respond_id, &msg_arg,sizeof(msg_arg), 0);
                        printf("%d barber is serving for %d customer \n", getpid(), msg_arg.mid);
                        
                        down(account_sem);
                        printf("%d barber is collect %d customer's money\n", getpid(), msg_arg.mid);
                        up(account_sem);
                   } else {
                        printf("%d barber is sleeping\n", getpid());
    
                   }
                }
            }
        }
        return 0;
    }
    
    
    

    编译:

    gcc -g -c Barber.c ipc.c
    gcc Barber.o ipc.o -o barber
    gcc -g -c Customer.c ipc.c
    gcc Customer.o ipc.o -o customer
    
    

    运行:

    在根目录下打开两个命令窗口,分别执行
    ./barber 
    ./customer
    
    展开全文
  • 操作系统中PV操作之顾客理发师问题

    万次阅读 2018-03-27 17:42:36
    0,进程被唤醒理发师问题 一个理发师,一把理发椅,n把等候理发的顾客椅子,如果没有顾客则理发师便在理发椅上睡觉 ,当有一个顾客到达时,首先看理发师在干什么,如果理发师在睡觉,则唤醒理发师理发,如果理发师...
     
     

    PV操作:对信号量进行相应操作

    S:信号量

    P:请求操作,相当于S=S-1;S>=0,进程继续进行

    V:释放操作,相当于S=S+1,S>0,进程被唤醒

    理发师问题 

    一个理发师,一把理发椅,n把等候理发的顾客椅子,如果没有顾客则理发师便在理发椅上睡觉 ,当有一个顾客到达时,首先看理发师在干什么,如果理发师在睡觉,则唤醒理发师理发,如果理发师正在理发,则查看是否有空的顾客椅子可坐,  如果有,坐下等待,如果没有,则离开。 

    定义信号量:wait=0:顾客信号量   barber=0:理发师信号量

                       custNum:当前顾客数量   mutex=1:互斥量

    理发师操作:

    Barber(){

    while(1){

            P(wait);    //唤醒等待的一位顾客

            P(mutex);  //顾客被唤醒,准备理发,没有顾客,则睡觉

            custNum--;    //当前店里顾客数减1

             V(barber);   //有顾客来了,醒来理发

            V(mettux):   //释放互斥信号量

    }

    }

    顾客操作:

    Customer(){

    while(1){

    P(mutex);    //顾客想要理发

    if(custNum<N){   //店里人没有满

         custNum++;

         V(wait);     //理发师睡觉的话,唤醒他理发

         V(mutex);    //释放互斥量,理发这一动作成功

         P(baber);    //理发师进行理发操作

    }

    else

    {

           V(metux);    //释放互斥量,打消进店理发的举动

    }

    }

    }

    展开全文
  • 操作系统实验中的线程同步和互斥问题理发师基础版问题解决
  • The Sleeping-Barber Problem. A barbershopconsists of a waiting room with n chairs and the barber room containing thebarber chair. If there are no customers to be served, the barber goes to sleep.If a

    The Sleeping-Barber Problem. A barbershopconsists of a waiting room with n chairs and the barber room containing thebarber chair. If there are no customers to be served, the barber goes to sleep.If a customer enters the barbershop and all chairs are occupied, then thecustomer leaves the shop. If the barber is busy but chairs are available, thenthe customer sits in one of the free chairs. If the barber is asleep, thecustomer wakes up the barber. Write a program to coordinate the barber and the customers.


    Int wait =0;

    Int chairs=n;

    Int babers=0;

    Semaphore customs=0, babers=0, mutex=1;

     

    Baber(){
             while(true);

             P(customers);//服务一个顾客

             P(mutex);//进入临界区

             Waiting:=waiting-1;//等待顾客数-1

             V(babers);//理发师临界区开放

             V(mutex);//开放临界区

             Cut_hair();//理发

    }

     

    Customer(){

             P(mutex);//进入临界区

             If(waiting<=chairs){

                       Waiting:=waiting-1;//没有超过则等待人数+1

                       V(babers);//唤醒一下理发师

                       V(mutex);//开放临界区

                       P(babers);//使用理发师

                       Get_haircut();//理发

             }

             ElseV(mutex); //如果等待人数超过椅子数,离开

    }

    展开全文
  • 操作系统经典问题理发师问题

    千次阅读 2019-04-03 17:02:20
    理发师问题描述如下: 理发店包含一间接待室和一间工作室,有一名理发师,接待室内有n(n≥1)把椅子,而工作室只有1把椅子。如果没有顾客,理发师就去睡觉;如果理发师在睡觉;则顾客会唤醒他;如果理发师在忙且接待...
  • 进程同步问题
  • 操作系统多线程经典问题,顾客理发师问题理发师1位,顾客、椅子的数量可以自定义。没有顾客时: 理发师永远睡觉 新顾客到来时: 若椅子满了,新顾客离开 若椅子没满,新顾客等待;若理发师工作完,新顾客理发
  • 理发师问题: 理发店理有一位理发师、一把理发椅和n把供等候理发的顾客坐的椅子 如果没有顾客,理发师便在理发椅上睡觉 一个顾客到来时,它必须叫醒理发师 如果理发师正在理发时又有顾客来到,则如果有空...
  • 睡眠的理发师问题

    千次阅读 2018-11-30 13:50:16
    ​ 睡眠的理发师问题操作系统中P、V操作部分的经典问题 睡眠的理发师问题 1. 问题描述 理发店理有一位理发师、一把理发椅和n把供等候理发的顾客坐的椅子,要求: 如果没有顾客,理发师便在理发椅上睡觉 一个顾客...
  • #define CHARIS 5 //椅子数目 int waitings=0; ------------------------------------------------- 信号量一定要赋初值 ------------------------------------------------- semaphore barber=0,customer=0;...
  • 理发师问题 问题描述:理发店里有一位喜欢睡觉的理发师、一把理发椅和n个等待位。若没有顾客,理发师便在理发椅上睡觉,当有顾客到来时,他就被顾客唤醒并为其服务。...理发师问题用P,V操作叙述如下: ...
  • 进程同步之理发师问题

    万次阅读 多人点赞 2016-08-07 12:50:41
    进程同步之理发师问题@(操作系统)[进程同步]description假设有一个理发店只有一个理发师,一张理发时坐的椅子,若干张普通椅子顾客供等候时坐。没有顾客时,理发师就坐在理发的椅子上睡觉。顾客一到,他不是叫醒理发...
  • 操作系统经典例题《理发师问题》升级版的超详尽攻略!
  • 这是睡眠理发师问题加强版的Java解决方案参考,是一次操作系统实验的分析报告。实验问题完整描述可参考实验完整描述以及要求文档。实验的完整代码可参考Demo。 理发师问题描述: 一个理发店由一个有n个椅子的等候室...
  • 问题描述:熟睡的理发师问题描述的是多个进程(线程)之间的通信与同步问题:有一个理发师的椅子,和n个顾客的椅子如果有顾客在椅子上等,那么理发师为他剪发,否则理发师就在自己的椅子上睡觉。如果理发师在熟睡,那么...
  • 睡眠的理发师问题 ** 问题描述 理发店理有一位理发师、一把理发椅和n把供等候理发的顾客坐的椅子,要求: 如果没有顾客,理发师便在理发椅上睡觉 一个顾客到来时,它必须叫醒理发师 如果理发师正在理发时又有顾客...
  • 信号量PV经典问题之沉睡理发师,适用操作系统大作业 C++编写
1 2 3 4 5 ... 20
收藏数 1,112
精华内容 444
关键字:

理发师问题操作系统