操作系统课程设计
超市购物模拟
组别:
组员: 编程
设计报告
汇报 , PPT
南通大学·计算机科学与技术学院
2018年06月
摘 要
本设计采用了visual c++ 6.0开发工具,解决了模拟超市购物中控制并发线程同步与互斥的问题,实现了线上模拟超市购物的功能:包括开放超市,顾客排队进入超市,选用购物车,顾客随机选购商品,排队购买熟食,排队付款,付款方式选择,折扣优惠,结账等。模拟超市购物中主要运用Windows线程同步与控制,信号量和互斥体,派生类等方法实现其相应功能。经分析表明,程序逻辑正确。程序具有正确性,可读性,高效性,健壮性等特点。
关键词:Windows 线程创建、控制、同步与互斥、超市购物模拟、互斥体、信号量。
目 录
课设名称:超市购物模拟
编程环境:visualC++ 6.0
编程语言:visualC++
设计报告:OFFICE2013 之 word
汇报方档:OFFICE2013 之 Power Point
1.问题描述
1.1超市购物模拟中待解决的问题
编写一个程序,用线程控制和线程同步(使用互斥体和信号量)机制来模拟超市购物的运转情况,
模拟超市购物的运转过程中有以下角色:超市管理员,购物车,顾客,结账柜台,熟食柜台店员,商品,熟食。模拟超市购物需要实现的功能有:选择购物车(新增),管理员开放超市,管理员线程创建顾客线程,顾客线程排队进入超市,顾客自由选购商品(包括是否选择熟食),选购完毕之后进入队列,等待付款,多种付款方式选择(新增),折扣优惠活动(新增),完成付款后离开超市。本次模拟购物完成。其中超市管理员和顾客用线程机制建立,管理员的线程创建顾客线程,顾客线程并发执行需使用同步机制,(如信号量等,互斥体关于互斥体:互斥体是一个可命名的安全内核对象,其目的是控制线程护持地访问临界资源,作为内核对象,互斥体必须被创建,打开后才能使用)。模拟购物过程中要建立三个队列,队列1是等待进入超市队列,队列2是购买熟食队列,还队列3是等待付款的队列。
图1-1,模拟超市购物流程图
2.分析及功能设计
2.1vsm.h是基本的变量和函数的定义,创建线程类class MyThread,超市管理员的线程类和顾客类的线程类,是最基本的变量和函数的的定义。其中由父类MyThread派生的子类超市管理员线程主体class SuperMarket和顾客线程主体class Customer;并在各个类中定义实现相应功能的变量和函数,下面讲述超市管理员线程和顾客线程中的变量和函数的定义:
(1)超市管理员线程的功能主要是开放超市;创建各个顾客线程,由信号量来控制创建顾客线程的数量;关闭超市;及在结束模拟之前,等待商店中所有顾客付钱离开。伪代码描述如下:
class SuperMarket:public MyThread//定义了超市管理员线程
{//超市线程主体
public:
void output(string os);//开启超市
SuperMarket();virtual void run ();//超市行
};
(2)由超市管理员线程创建顾客线程,最多创建的顾客线程MAXCUS数量为20个,在顾客线程进入超市之前需等待超市开放。超市开放后,顾客排队进入超市,允许进入超市的顾客共15个,为控制进入超市的顾客数量最多为CUSINMAR(15个),还需创建ThreadNumMutex信号量进行控制其余等待。进入超市的这些顾客共同享有购买超市中物品的机会,每个顾客购买商品的时间和数量是由随机数产生的;在模拟购物中,如果顾客需要购买熟食,此时必须要到购买熟食的队列排队,且队列的排队人数MAXQUEUE最多为5个;每次熟食柜台仅为一位顾客服务,因此熟食柜台需要互斥使用,在熟食柜台处创建CookMutex互斥体,控制顾客互斥的到熟食队列购买熟食。无论顾客是否购买熟食,在选购商品完毕后,顾客需要在柜台处排队进行付款;柜台数目有三个,因此顾客可以排成三个队列,且每个队列的人数MAXQUEUE最多为五个,且每个柜台每次仅能为一个顾客结账,因此需要创建AccessCounter互斥体,控制互斥的访问柜台counter。(注:顾客购买商品的种类数量及是否购买熟食,到哪个柜台结账,结账次序均是由随机数产生)在顾客结账时随机选择在结账处的花费,在结账处新增选择支付方式功能和折扣优惠功能,结账完毕后,顾客线程离开超市,本次模拟购物完成。各变量功能说明如下表:
信号量/互斥体/变量 |
对信号量或互斥体说明功能 |
ThreadNumMutex:信号量 |
控制进入超市的顾客最多为CUSTINMAR |
CounterMutex[]:互斥体 |
控制互斥地到MAXCONTER个柜台结账 |
AccessCounter:互斥体 |
控制互斥的访问柜台counter [] |
CookMutex:互斥体 |
控制互斥访问巧随机生成购买东西的次数和是否到熟食柜台买熟食并随即生成访问次序 |
AccessCookCounter:互斥体 |
控制互斥的访问熟食柜台cookcounter |
counter[] |
统计到各个结账柜台排队的顾客数目MAXCOUNTER |
cookcounter |
统计到熟识队列排队的顾客数cookcounter,并判断是否可以继续排队 |
countertime |
每个顾客的结账时间 |
cost |
顾客的消费总额 |
CookMutex:互斥体 |
控制熟食柜台被互斥访问 |
表1,变量功能说明
2.2vsm.cpp文件夹中对应的函数和变量功能分析
vsin. Cpp是整个程序中的核心运行部分,控制整个函数的运转和各个功能的实现,在启动超市运作后,通过每个函数对应的句柄及函数体本身完成相应的功能,实现功能包括:开启超市运作,通过超市管理员线程创建顾客线程;顾客线程执行的相应活动,随机选购商品(选购时间数量随机),随机进入熟食队列购买熟食;选购完毕后排队进行付款(排队序列由随机数产生);通过信号量或互斥体来控制进入超市的人数,每个队列的人数,购买熟食的人数等;由以下函数完成模拟超市购物功能,下表描述了个函数所对应的功能:
函数名 |
功能 |
void SuperMarket::run() |
超市运作启动函数 |
void SuperMarket::output(string os) |
辅助函数 |
void MyThread::start() |
开始创建线程函数 |
void MyThread:WaitForCompletion() |
由线程申请的P操作函数 |
Void Customer::Shopping() |
处理贵客随机购物的函数,该函数给countertime赋值根据购买品的多少 ,回顾客结账的时间 |
Void Customer::run() |
顾客到来随机购物的函数 |
void Customer::setCustomerNumber(); |
设置顾客人数 |
void Customer::handlecounter() |
处理顾客结账的函数 |
void Custmer::setCounter() |
创建各个柜台结账的线程 |
Handlecounter() |
处理顾客结账排队的函数 |
表2,函数功能说明
2.3增加功能分析
(1)增加功能1:是否需要购物车(随机数实现)
Const char CAR[10][16]={"需要购物车","不需要购物车"};//是否需要购物车
int n=get_random()%2;
printf("user%s come in market.,car:%s\n",myname.c_str(),CAR[n]);
fflush(stdout);
(2)增加功能2:支付方式选择(随机数实现)
const char PAYWAY[10][8]={“刷卡”,”现金”,”支付宝”};//选择支付方式
int j=0;j=get_random()%3;
printf("user%s come to counter%d,pay money%d,pay discount money%d,
pay way%s\n",myname.c_str(),min,cost,discountcost,PAYWAY[j]);
(3)增加功能3:满500元打折活动
unsigned long intcost; //顾客消费的总额
unsigned long intdiscountcost; //满500元打完折后的金额
if(cost>500)
{
discountcost=((cost*9)/10);
}
else
discountcost=cost;
(4)增加功能4:界面设计,如下所示
cout<<"\t------------------------------------------------\n";
cout<<"\t************欢迎查看本次超市购物流程************\n";
cout<<"\t------------------------------------------------\n";
3测试用例及其求解
(1)测试数据如表3,(注:顾客购买商品的种类数量及是否购买熟食,到哪个柜台结账和结账次序均是由随机数产生,依照表格改变相应数据,测试代码的正确性)
序号 |
最多创建的顾客线程数 |
最多进入超市的顾客数 |
各队列的最大长度 |
货物的种类数 |
结账柜台数 |
是否与运行结果一致 |
1 |
20 |
15 |
5 |
5 |
3 |
是 |
2 |
10 |
5 |
2 |
5 |
2 |
是 |
3 |
25 |
20 |
6 |
5 |
3 |
是 |
4 |
30 |
25 |
6 |
5 |
4 |
是 |
表3,测试数据
(2)表1-1中序号2所对应数据的测试结果如下:图1-2
图1-2序号2对应数据的运行结果
(3)表1-1中序号3所对应数据的测试结果如下:图1-3
图1-3序号3对应数据的运行结果
(2)表1-1中序号4所对应数据的测试结果如下:图1-4
图1-4序号4对应数据的运行结果
4程序设计
4.1逻辑结构设计
(1)对于逻辑结构,有线性结构中的特殊线性结构——队列,在本项目中使用了三次队列(均为普通队列),分别是:进入超市队列,购买熟食队列,付款队列。(注:队列只允许在表的一端进行插入和另一端进行删除,允许插入的一端是队尾(rear),允许删除的一端的队头,队列元素从队尾插入称入队,从队头删除称出队),三个队列元素均为顾客线程,用元素Customer表示顾客线程,则三个队列工作情况表示如下图1-5:
(2)在程序中用到的逻辑结构还有对于商品和商品价格是一一对应的线性结构,在模拟超市购物中,商品的种类是5种,相对应的价格为五种,两者关系如图1-6所示:
图1-6,商品及价格对应
4.2 存储结构设计
在本程序中所有元素均采用顺序存储方式,在逻辑上相邻的元素存储在物理位置也相邻的存储单元中,例如存放在超市购物架上的各类商品,他们物理位置相邻,相应的逻辑存储单元也相邻,因此商品数量采用顺序存储实现。相应地,每种商品的价格与商品一一对应,商品价格同样采用顺序存储;队列中顾客线程也是顺序存储,顾客与顾客之间物理位置相邻,逻辑位置也相邻。对于采用数序存储的的各元素,在程序中,采用数组来实现,顾客表示为counter[];商品价格表示为PRICE[G00DS+1]= {5,100,12, 30,500,7}, 其中第0项为熟食价格,第1项-5项表示其他5种商品的价格;商品的数量MAXQ0ANTITY[GOODS+1]={5,2,10,5,1,7},其中第0项代表熟食的数量,第1-5项代表其他五种商品的数量。
4.3 算法设计
4.31数据结构
所采用的逻辑结构为线性结构中的队列,采用的存储结构为顺序存储,用数组实现,参见4.1,4.2
4.32算法
(1)随机数,有随机数产生是否需要购物车,选购商品的种类,数量,及选购商品时间。
(2)乘法:商品的价格计算有商品种类相对应的价格乘以商品的数量
(3)父类和子类:父类MyThread派生的子类超市管理员线程SuperMaket和顾客线程主体Customer,如图1-7所示:
图1-7,父类和子类
(4)互斥体和互斥量:参见变量定义和功能表1
4.33算法评价
算法可正确执行,可实现模拟购物中的相应功能,具有正确性;算法中有详细注解,具有较高的可读性;从算法采用的逻辑结构和存储结构来看,只能顺序访问,对于在队列中任意位置执行删除和插入操作来说,比较复杂,算法中仍存在需改进的地方;算法的功能有待扩展,具有可扩展性。
4.4 界面设计如下图所示:图1-8
图1-8,界面设计
5程序运行情况
(1)样例程序运行结果,图1-9
图1-9,样例程序运行结果
(2)添加折扣功能运行截图:图1-10
图1-10,折扣功能
(3)添加支付方式功能运行截图:图1-11
图1-11,支付功能
(4)添加购物车功能运行截图:图1-12
6.小结
在本次课程设计中,我们组的3名成员齐心协力共同完成了此次任务。我们分工明确,其中李xx负责编程,谢xx负责文档设计,王xx负责PPT制作。积极合作,在不懂的问题上大家共同讨论,求解问题。在本次课设中,我懂得了团队合作的重要性,相互学习交流的必要性,这样才能获得成长!
(流程图没有截完整,是两张拼凑在一起的,有需要源码的朋友留言)
7.附录:参考文献
[1]徐慧. 数据结构实践教程[M]. 清华大学出版社, 2010.
[2] 费翔林, 骆斌. 操作系统教程.第5版[M]. 高等教育出版社, 2014.
[3] 陈建平, 刘维富, 葛建芳. C++程序设计教程[M].高等教育出版社, 2007.
[4]张丽芬, 刘昕, 刘利雄. 操作系统实验教程及Linux和Windows系统调用编程[M]. 清华大学出版社, 2010.
[5]数据的逻辑结构和存储结构:
https://blog.csdn.net/zwz2011303359/article/details/62887670?locationNum=5&fps=1
[6] 经典同步互斥问题:https://blog.csdn.net/u012814856/article/details/56304773
[7]线程同步作用: https://blog.csdn.net/gsdferterfg465/article/details/10363681