当前位置:文档之家› 银行排队系统

银行排队系统

1、编程实现一个“银行排队模拟系统”思想:程序等待标准输入,若检测到有标准输入,则创建对应的进程。

如果目前等待态的进程个数等于座位数,在门外等待(即放入消息队列等待创建);若目前阻塞的进程个数小于座位数则进程阻塞。

与此同时,检测等待态的进程个数小于座位数,消息队列中存在消息,则从消息队列中取出一条消息,同时创建一个新进程。

本程序使用信号量进行进程间通信,使用消息队列存储从stdin输入的消息。

设置一信号量,标示大厅中座位。

设置一消息队列,标示在门外等待。

本程序,没有实现,老师所说的,“窗口进程”。

只是在主控进程中,对S3,S4进行了操作来实现与子进程的通信。

相当于,主控进程作为一个窗口进程,来处理各个客户进程。

由于,想要做到,在同一时间,主控进程最多只有两个子进程(客户进程)在执行,其他的都在阻塞状态,因此,本程序,将S3的初始值设置为21) 该程序模拟客户到银行取号-排队-被叫号-被服务的过程;2) 程序执行流程如下:Step1: 客户到达银行,并从取号机取号;Step2: 如果大厅中有空闲座位,则座下等待,否则,在大厅外等待;Step3: 银行职员如果发现有客户等待,则依次叫号服务,否则休息;Step4: step1-step4重复执行3) 大厅中座椅数量为20个;4) 服务窗口为2个;5) “客户到来”通过命令行输入客户名字模拟;6) 为了模拟实际情况,每个客户服务时间不小于20秒,可随机确定;7) 程序顺序列出不同窗口服务客户的:名称,窗口号,服务时间2、提示1) 需一个主控进程,随时监控客户到来,并为之创建进程;2) 取号机应视为互斥型临界资源3) 座椅应视为临界资源4) 客户等待及被叫号应视为进程间同步过程主控进程(serve.c)执行流程图:客户端进程(client.c)执行流程图:需求分析:本系统,没有实现,窗口进程,最初目的在于,保证在同一时间,父进程即主控进程最多具有2个子进程在执行。

本模拟系统需要两个程序,一个作为主控进程,负责宏观调度(检测是否有标准输入,如果有,则创建子进程···);一个作为子进程,负责输出服务窗口(自己的PID),系统对自己的服务时间,自己等待系统服务的时间,(也可输出自己的名称,此处的传值方式与信号量的ID原理相同,因此省去本项)。

PS:此程序以实现serve.c 为主控进程client.c为子进程,子进程的二进制文件名必须为client,绝对路径必须为“mnt/usb/signal”如果想要修改,可以参看课本execle函数的使用守则del.c如果主控进程异常退出但是有没有执行删除消息队列,信号量集合是使用,记得修改参数serve.c#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/times.h>#include<sys/ipc.h>#include<sys/msg.h>#include<sys/sem.h>#include<setjmp.h>jmp_buf crt;//设置跳转节点jmp_buf end;char *env_init[]={"USER=root","PATH=/mnt/usb",NULL};//初始化环境表中的信息union semun//使用信号量函数,我们必须自己定义semun 联合类型。

{int val;struct semid_ds *buf;unsigned short *array;};struct msgsbuf//定义向消息队列发送消息的结构体{int mtype;char mtext[10];}msg_sbuf;struct msgmbuf//定义从消息队列接收消息的结构体{int mtype;char mtext[10];}msg_rbuf;int crt_msg(key_t key)//创建一个消息队列,如果出错则跳转到出错处理程序,如果没有出错,则返回创建的消息队列的ID{int msgid;msgid=msgget(key,IPC_CREA T|00666);//如果已存在msgid这个值的消息队列,不阻塞,直接打开,如果不存在则根据key的值新建一个消息队列//msgid=msgget(key,IPC_CREAT|IPC_EXCL|00666);//接受从主函数传递过来的KEY创建一个消息队列,此处设置为:如果已存在该队列则出错返回if(msgid<0)//判断是否出错{printf("create message error!\n")longjmp(end,1);//如果出错,跳转到setjmp(end)语句的下一句,开始执行程序。

}return msgid;//返回创建的消息队列的ID}int crt_sig(key_t key,int nsems)//创建一个信号量集合,如果出错则跳转到出错处理程序,如果没有出错,则返回创建的信号量集合的ID{int sigid;sigid=semget(key,nsems,IPC_CREAT|00666);//如果已存在msgid这个值的信号量集合,不阻塞,直接打开,如果不存在则根据key的值新建一个信号量集合//sigid=semget(key,nsems,IPC_CREAT|IPC_EXCL|00666); //此处设置,如果已存在semid的信号量集合,则出错返回if(sigid<0)//判断是否出错{printf("create signal set error!\n");longjmp(end,1);//如果出错,跳转到setjmp(end)语句的下一句,开始执行程序。

}return sigid;//返回创建的信号量集合的ID}pid_t crt_child()//创建一子进程,如果出错,则跳转到setjmp(end)的下一句开始执行,如果没有出错,则返回新建子进程的ID{pid_t pid;if((pid=fork())<0)//判断是否出错{printf("create child error!\n");longjmp(end,1);//如果出错,跳转到setjmp(end)语句的下一句,开始执行程序。

}return pid;//返回创建的子进程的ID}int msg_stat(int msqid,struct msqid_ds msg_info)//查看消息队列的基本信息,本子函数也可用于测试对消息队列数据的传输是否正常,出错则跳转到setjmp(end)的下一句开始执行,返回消息队列成员的个数{int reval;sleep(1);reval=msgctl(msqid,IPC_STA T,&msg_info);if(reval<0)//判断是否出错{printf("get message informatioin error!\n");longjmp(end,1);//如果出错,跳转到setjmp(end)语句的下一句,开始执行程序。

}return msg_info.msg_qnum;//返回消息队列成员的个数}int sig_blk_num(int semid)//查看因等待信号量集合ID为semid的信号集中的第二个信号为1而阻塞的进程的个数,并将该个数返回{int reval;reval=semctl(semid,2,GETNCNT);//获取因等待信号量集合ID为semid的信号集中的第二个信号为1而阻塞的进程的个数return reval;//返回因等待信号2而阻塞的进程个数}int get_sig_value(int semid,int num)//获取信号量集合ID为semid的集合的第num个信号的值,并将该值返回{int reval;reval=semctl(semid,num-1,GETVAL);//获取函数if(reval==-1)//判断是否出错{printf("get signal set %dth member's value error!\n");longjmp(end,1);//如果出错,跳转到setjmp(end)语句的下一句,开始执行程序。

}return reval;//返回semid信号集合的第num个成员的值}void sig_wait(int semid,int num)//对semid信号集合的第num个信号进行P(减一)操作,如果出错,则跳转到setjmp(end)的下一句开始执行,无返回值{printf("this is sig_wait semid=%d num=%d\n",semid,num);int reval;struct sembuf operation;//定义sembuf结构体operation.sem_num=num-1;//定义是semid信号集合的信号的下标,即对第num个信号进行操作operation.sem_op=-1;//执行P操作(减一)operation.sem_flg=SEM_UNDO;//如果不能对该信号进行操作(该资源已被占用),则阻塞,等待该信号的值为semop函数的第三个参数reval=semop(semid,&operation,1);//具体操作函数if(reval<0)//判断是否出错{printf("wait signal error!\n");longjmp(end,1);//如果出错,跳转到setjmp(end)语句的下一句,开始执行程序。

}}void sig_post(int semid,int num)//对semid信号集合的第num个信号进行V(加一)操作,如果出错,则跳转到setjmp(end)的下一句开始执行,无返回值{int reval;struct sembuf operation;//定义sembuf结构体operation.sem_num=num-1;//定义是semid信号量集合的下标,即对第num个信号进行操作operation.sem_op=1;//执行V操作(加一)operation.sem_flg=SEM_UNDO;//如果不能对该信号进行操作,则阻塞reval=semop(semid,&operation,1);if(reval<0)//判断是否出错{printf("post signal error!\n");longjmp(end,1);//如果出错,跳转到setjmp(end)语句的下一句,开始执行程序。

相关主题