Linux操作系统利用信号量实现银行叫号排队系统.docx

上传人:b****7 文档编号:9826266 上传时间:2023-02-06 格式:DOCX 页数:32 大小:550.76KB
下载 相关 举报
Linux操作系统利用信号量实现银行叫号排队系统.docx_第1页
第1页 / 共32页
Linux操作系统利用信号量实现银行叫号排队系统.docx_第2页
第2页 / 共32页
Linux操作系统利用信号量实现银行叫号排队系统.docx_第3页
第3页 / 共32页
Linux操作系统利用信号量实现银行叫号排队系统.docx_第4页
第4页 / 共32页
Linux操作系统利用信号量实现银行叫号排队系统.docx_第5页
第5页 / 共32页
点击查看更多>>
下载资源
资源描述

Linux操作系统利用信号量实现银行叫号排队系统.docx

《Linux操作系统利用信号量实现银行叫号排队系统.docx》由会员分享,可在线阅读,更多相关《Linux操作系统利用信号量实现银行叫号排队系统.docx(32页珍藏版)》请在冰豆网上搜索。

Linux操作系统利用信号量实现银行叫号排队系统.docx

Linux操作系统利用信号量实现银行叫号排队系统

Linux操作系统课程设计

 

题目:

进程通信与进程同步机制实践

(银行叫号排队模拟系统)

 

所在学院:

所在班级:

学生姓名:

学生学号:

指导教师:

一、题目

某银行提供5个服务窗口(3个对私服务窗口,1个对公服务窗口,1个理财服务窗口)和10个供顾客等待的座位。

顾客到达银行时,若有空座位,则到取号机上领取一个号,等待叫号;若没有空座位,则在门外等待或离开.取号机每次仅允许一位顾客使用,有对公、对私和理财三类号,每位顾客只能选取其中一个.当营业员空闲时,通过叫号选取一位顾客,并为其服务。

请用P、V操作写出进程的同步算法。

二、目的

1、掌握基本的同步与互斥算法。

2、学习使用Linux中基本的同步对象,掌握相关API的使用方法。

3、了解Linux中多任务的并发执行机制,实现进程的同步与互斥。

三、实验环境

LinuxCentOS、Ubuntu、Fedora等Linux系统

编译器GCC

编程语言C语言

四、要求

1、当有顾客取号的时候,不允许其他顾客取号。

2、当服务窗口满的情况下,其他人必须等待.

3、当没有顾客的情况下,服务窗口必须等待。

4、打印:

A、初始状态

B、中间变化的状态信息

C、以及最终状态信息。

五、原理及算法

本程序中设计6个信号量,其中signal_A、signal_B和signal_C分别是对私、对公、理财窗口的同步信号量。

若信号量值的等于0,说明当前没有空闲空口,顾客需要等待。

另设置一个signal_seat同步信号量,记录当前的座位情况,若该信号量等于0,说明当前没有空座位,顾客需要等待。

另有一个signal_customer同步信号量用于记录当前已经取过票的总人数,用于生成票号信息。

还有一个mutex互斥信号量,用于实现各进程在对信号量进行操作时的互斥。

顾客进入银行之后,先看通过一个依据系统时间的随机数来确定自己是需要对私、对公还是理财服务(在本程序中分别对应于A类顾客,B类顾客和C类顾客),这三个类型的顾客的比例为3:

1:

1.然后顾客根据自己需要的服务类型,查看提供相应类型服务的窗口是否空闲,若窗口有空闲,则系统直接按照signal_customer记录的信息,生成票面信息;若窗口没有空闲,则再去查看signal_seat信号量看看是否有空座位,若有空座位,则根据signal_customer记录的信息,生成票面信息;若没有空座位,则通过一个以系统时间为种子的随机数生成器生成一个随机数,帮助顾客确定是要继续等待还是离开,这两种情况的比例为1:

1.若顾客选择离开,则相应的进程退出.

当顾客取到票后,便开始查看对应类型的窗口是否有空闲,如果有空闲,则上前办理业务。

顾客办理业务需要的时长通过以系统时间为种子的随机数生成器来确定,时长均在10秒到60秒之间。

在程序执行的过程中,顾客的状态每有变换,都会有相应的输出提示信息,并在输出的行尾输出发生该动作时当前的系统时间,以便于我们分析各个顾客进程的执行情况。

本实验在Linux环境下完成,该程序是通过进程实现的.包含一个service可执行文件,一个customer可执行文件和一个deletesem可执行文件。

其中service可执行文件用于在内存中申请一个共享内存空间,并将这个内存空间与自身进程绑定;customer可执行文件每执行一次,就增加一个进程,即代表有一位顾客来到.通过多次执行customer可执行文件来模拟多位顾客;deletesem可执行文件用于在service进程和customer进城都执行完毕后,删除内存空间中的信号集。

实验中利用GCC编译器,通过编写Makefile文件来快速编译源代码生成以上三个可执行文件。

六、程序中各主要函数说明

1、intcreateshm(char*pathname,intproj_id,size_tsize)

创建共享内存的函数,操作成功则返回共享内存标识符,失败返回-1.

2、intcreatesem(constchar*pathname,intproj_id,intmembers,intinit_val[])

在共享内训中创建信号量的函数,操作成功则返回信号集标识符,失败返回-1.

3、intopensem(constchar*pathname,intproj_id)

打开信号集函数,操作成功则返回信号集标识符,失败返回-1。

4、intsem_p(intsemid,intindex)

P操作函数,操作成功则返回0,失败返回—1.

5、intsem_v(intsemid,intindex)

V操作函数,操作成功则返回0,失败返回-1。

6、intwait_sem(intsemid,intindex)

等待信号量为1函数,操作成功返回1.

7、intdelete_sem(intsemid)

删除信号集函数,操作成功返回0。

8、intget_sem_val(intsemid,intindex)

获取指定信号集中指定下标的信号量的值,操作成功返回该信号量的值。

9、intmy_random()

自定义随机数生成器,以系统时间为种子,每次执行前延时1秒,以便于生成不同的随机数。

10、voidprint_time()

打印当前系统时间。

11、intget_ticket(intsemid,charidentifyLabel,int*ticket,int*flag)

顾客取票函数,取票成功,返回1,失败返回-1,,由于没有空座,顾客选择离开则返回0.

12、voidservice(intsemid,charidentifyLabel,int*ticket,int*flag)

顾客办理业务函数。

七、源程序清单

sharemem。

h文件

#include〈stdio。

h〉

#include

#include

h>

#include〈sys/types.h〉

#include〈sys/ipc。

h>

#include

#include〈sys/shm.h>

#include

#include〈time。

h〉

#defineSHM_SIZE1024

#defineINDEX_MUTEX0

#defineINDEX_SIGNAL_SEAT1

#defineINDEX_SIGNAL_CUSTOMER2

#defineINDEX_SIGNAL_A3

#defineINDEX_SIGNAL_B4

#defineINDEX_SIGNAL_C5

/*定义信号量*/

/*同步信号量一共有4个*/

intsignal_A=3,signal_B=1,signal_C=1,signal_seat=3,signal_customer=0;

/*互斥信号量mutex控制进程对每个同步信号量的操作*/

intmutex=1;

intsignal_count=6;//信号量计数器,记录一共有多少信号量

 

unionsemun

{

intval;

structsemid_ds*buf;

unsignedshort*array;

};

/*创建共享内存函数*/

intcreateshm(char*pathname,intproj_id,size_tsize)

{

key_tshmkey;

intsid;

/*获取键值*/

if((shmkey=ftok(pathname,proj_id))==—1)

perror("ftokerror!

\n");

exit

(1);

return-1;

}

if((sid=shmget(shmkey,size,IPC_CREAT|0666))==-1)

{

perror("shmgetcallfailed。

\n”);

exit

(1);

return-1;

return(sid);

}

/*定义创建信号量的函数*/

intcreatesem(constchar*pathname,intproj_id,intmembers,intinit_val[])

key_tmsgkey;

intindex,sid;

unionsemunsemopts;

if((msgkey=ftok(pathname,proj_id))==—1)

perror(”ftokerror!

\n");

exit

(1);

return-1;

if((sid=semget(msgkey,members,IPC_CREAT|0666))==—1)

perror(”semgetcallfailed.\n”);

exit

(1);

return—1;

}

/*对信号量进行初始化操作*/

for(index=0;index

semopts.val=init_val[index];//根据init_val数组中的值对各个信号量进行初始化

semctl(sid,index,SETVAL,semopts);

}

return(sid);

}

/*打开信号量函数*/

intopensem(constchar*pathname,intproj_id)

{

key_tmsgkey;

intsid;

if((msgkey=ftok(pathname,proj_id))==-1)

{

perror(”ftokerror!

\n");

exit

(1);

return—1;

}

if((sid=semget(msgkey,0,IPC_CREAT|0666))==—1)

{

perror(”semgetcallfailed。

\n”);

exit

(1);

return-1;

}

return(sid);

}

 

/*P操作函数*/

intsem_p(intsemid,intindex)

structsembufbuf={0,-1,IPC_NOWAIT};

if(index<0)

perror("indexofarraycannotequalsaminusvalue!

");

exit

(1);

return(-1);

}

buf.sem_num=index;

if(semop(semid,&buf,1)==—1)

perror(”awrongoperationtosemaphoreoccurred!

”);

exit

(1);

return-1;

return0;

 

/*V操作函数*/

intsem_v(intsemid,intindex)

structsembufbuf={0,+1,IPC_NOWAIT};

if(index〈0)

{

perror("indexofarraycannotequalsaminusvalue!

");

exit

(1);

return(-1);

}

buf。

sem_num=index;

if(semop(semid,&buf,1)==-1)

{

perror("awrongoperationtosemaphoreoccurred!

”);

exit

(1);

return(-1);

}

return0;

}

/*等待信号量为1函数*/

intwait_sem(intsemid,intindex)

{

while(semctl(semid,index,GETVAL,0)==0)

{

usleep(10000);

}

return1;

/*删除信号集函数*/

intdelete_sem(intsemid)

{

return(semctl(semid,0,IPC_RMID));

}

/*获取指信号量的值*/

intget_sem_val(intsemid,intindex)

returnsemctl(semid,index,GETVAL,0);

/*我的随机数生成器*/

intmy_random()

usleep(1000000);//延时函数,延时1秒,以便于生成不同的随机数

srand((unsigned)time(NULL));//初始化随机数生成器

return(rand());//调用随机数生成器生成并返回随机数

}

/*获取当前系统时间并靠右输出*/

voidprint_time()

time_tnow;//实例化time_t结构

structtm*timenow;//实例化tm结构指针

time(&now);//time函数读取现在的时间(国际标准时间非北京时间),然后传值给now

timenow=localtime(&now);//localtime函数把从time取得的时间now换算成你电脑中的时间(就是你设置的地区)

printf(”Time:

%s\n”,asctime(timenow));//asctime函数把时间转换成字符,通过printf()函数靠右输出

/*顾客取票函数,取票成功,返回1,失败返回-1,,由于没有空座,顾客选择离开则返回0*/

intget_ticket(intsemid,charidentifyLabel,int*ticket,int*flag)

intwait_num=0;

switch(identifyLabel)

{

case’A':

if(get_sem_val(semid,INDEX_SIGNAL_SEAT)==0)

{

if((wait_num=my_random()%10)〈5)

return0;//返回0表示顾客选择离开

printf("目前没有空座位,但该顾客选择了等待。

\n\n");

if(get_sem_val(semid,INDEX_SIGNAL_A)>0)//检查,如果有空窗口,则直接取票,不用判断座位

*flag=0;//将标志为设为0,标示没有顾客在等待,不用排队

gotogoto_A;//跳转到直接取票

if(wait_sem(semid,INDEX_SIGNAL_SEAT))//如果没有空座,则等待空座

sem_p(semid,INDEX_SIGNAL_SEAT);

goto_A:

if(wait_sem(semid,INDEX_MUTEX))//等待操作信号量释放

sem_p(semid,INDEX_MUTEX);//锁定操作信号量

*ticket=get_sem_val(semid,INDEX_SIGNAL_CUSTOMER)+1;//分配票号(票号是根据当天的总顾客数排的)

wait_num=(signal_seat—get_sem_val(semid,INDEX_SIGNAL_SEAT))-1;//获取当前等待的人数

printf(”号码:

A%03d,”,*ticket);

if(wait_num==0||*flag==0)

printf(”当前没有顾客正在等待。

\t");//wait_num大于等于0或者flag大于0,表示当前无人等待

print_time();

}

else

printf(”有%d位顾客正在等待。

\t”,wait_num);

print_time();

printf(”顾客A%03d正在等待办理业务。

\t”,*ticket);

print_time();

 

if(sem_v(semid,INDEX_SIGNAL_CUSTOMER)!

=0)//记录目前办理过业务和等待办理业务的顾客总数

{

printf("对不起,V操作失败!

”);

exit

(1);

return—1;

sem_v(semid,INDEX_MUTEX);//释放控制进程访问资源的信号量

break;

case’B':

if(get_sem_val(semid,INDEX_SIGNAL_SEAT)==0)

if((wait_num=my_random()%10)〈5)

return0;//返回0表示顾客选择离开

printf(”目前没有空座位,但该顾客选择了等待。

\n\n”);

if(get_sem_val(semid,INDEX_SIGNAL_B)>0)//检查,如果有空窗口,则直接取票,不用判断座位

{

*flag=0;//将标志为设为0,标示没有顾客在等待,不用排队

gotogoto_B;//跳转到直接取票

}

if(wait_sem(semid,INDEX_SIGNAL_SEAT))//如果没有空座,则等待空座

sem_p(semid,INDEX_SIGNAL_SEAT);

goto_B:

if(wait_sem(semid,INDEX_MUTEX))//等待操作信号量释放

sem_p(semid,INDEX_MUTEX);//锁定操作信号量

*ticket=get_sem_val(semid,INDEX_SIGNAL_CUSTOMER)+1;//分配票号(票号是根据当天的总顾客数排的)

wait_num=(signal_seat—get_sem_val(semid,INDEX_SIGNAL_SEAT))-1;//获取当前等待的人数

printf("号码:

B%03d,",*ticket);

if(wait_num==0||*flag==0)

{

printf(”当前没有顾客正在等待。

\t");//wait_num大于等于0或者flag大于0,表示当前无人等待

print_time();

else

printf("有%d位顾客正在等待。

\t”,wait_num);

print_time();

}

printf("顾客B%03d正在等待办理业务.\t",*ticket);

print_time();

 

if(sem_v(semid,INDEX_SIGNAL_CUSTOMER)!

=0)//记录目前办理过业务和等待办理业务的顾客总数

{

printf(”对不起,V操作失败!

”);

exit

(1);

return—1;

}

sem_v(semid,INDEX_MUTEX);//释放控制进程访问资源的信号量

break;

case’C’:

if(get_sem_val(semid,INDEX_SIGNAL_SEAT)==0)

if((wait_num=my_random()%10)<5)

return0;//返回0表示顾客选择离开

printf(”目前没有空座位,但该顾客选择了等待.\n\n”);

if(get_sem_val(semid,INDEX_SIGNAL_C)〉0)//检查,如果有空窗口,则直接取票,不用判断座位

*flag=0;//将标志为设为0,标示没有顾客在等待,不用排队

gotogoto_C;//跳转到直接取票

}

if(wait_sem(semid,INDEX_SIGNAL_SEAT))//如果没有空座,则等待空座

sem_p(semid,INDEX_SIGNAL_SEAT);

goto_C:

if(wait_sem(semid,INDEX_MUTEX))//等待操作信号量释放

sem_p(semid,INDEX_MUTEX);//锁定操作信号量

*ticket=get_sem_val(semid,INDEX_SIGNAL_CUSTOMER)+1;//分配票号(票号是根据当天的总顾客数排的)

wait_num=(signal_seat—get_sem_val(semid,INDEX_SIGNAL_SEAT))—1;//获取当前等待的人数

printf(”号码:

C%03d,",*ticket);

if(wait_num==0||*flag==0)

{

printf("当前没有顾客正在等待。

\t");//wait_num大于等于0或者flag大于0,表示当前无人等待

print_time();

}

else

printf(”有%d位顾客正在等待。

\t”,wait_num);

print_time();

printf("顾客C%03d正在等待办理业务。

\t”,*ticket);

print_time();

 

if(sem_v(semid,INDEX_SIGNAL_CUSTOMER)!

=0)//记录目前办理过业务和等待办理业务的顾客总数

printf(”对不起,V操作失败!

");

exit

(1);

return—1;

}

sem_v(semid,INDEX_MUTEX);//释放控制进程访问资源的信号量

break;

 

}

return1;

/*顾客接受服务函数*/

voidservice(intsemid,charidentifyLabel,int*ticket,int*flag)

{

intneed_time=0;//用于记录

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 总结汇报 > 学习总结

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1