当前位置:首页 » 编程语言 » c语言餐厅管理系统

c语言餐厅管理系统

发布时间: 2024-09-23 01:01:35

① 餐厅桌台管理的c语言代码。

这是一个较大的系统,不可能几行代码就解决问题了的。

② 餐饮管理系统设计论文

餐饮行业在日常管理经营中仍然有很大一部分企业是在采取纯手工的管理模式,管理的整体科技含量较低。下面是我为大家整理的餐饮管理系统设计论文,供大家参考。

餐饮管理系统设计论文篇一

实体店餐饮管理系统设计与实现

餐饮管理系统设计论文摘要

摘要:随着我国市场经济的快速发展,人们的生活水平提高,餐饮业迅速蓬勃发展,传统的手工作业方式已经不能满足餐饮经营者的需求。通过餐饮管理系统对实体店进行管理,具有人工管理所无法比拟的优点,能够极大地提高餐饮管理的效率,增强企业的竞争力。

餐饮管理系统设计论文内容

关键词:餐饮;管理系统;数据库

一、引言

随着社会经济持续高速增长,社会财富迅速增加,广大人民群众收入水平不断提高,生活方式随之发生巨大变化。同时,随着市场经济体制的建立健全和迅速发展,社会物质产品极大丰富,餐饮业蓬勃发展,传统的手工作业方式已经不能满足餐饮经营者的需求了。人工记账、核算、查询等工作既费时、费力,也容易出错。通过在计算机中运行餐饮管理系统,既减少了人力资源,同时提高效率,能为餐饮业赚取更大的利润,同时为消费者提供了诸多方便。

近几年来,计算机网络、分布技术日趋成熟,随着科技的发展,餐饮业的竞争也越来越激烈。想在这样竞争激烈的环境下生存,就必须运用科学的管理思想与先进的管理 方法 ,使点餐与管理一体化。这样不仅可以提高工作效率,也避免了以前手工作业的麻烦,从而使管理者能够准确、有效地管理。因此,需要建立一个科学的餐饮管理系统。

二、系统分析

(一)可行性分析

1. 技术可行性

该系统是一个小型的餐饮管理系统。采用C/S模式,在前台计算机安装客户端,处理信息,将处理结果储存在数据服务器上。目前很多企业都采用SQL Server数据库,处理数据也相当方便,得到了广泛的应用,在技术上是可行的。

2. 经济可行性

对本系统的经济效益与开发成本进行分析。本系统采用C/S结构,只要拥有一台PC电脑,无需复杂设置即可实施,并且相对人工作业来说,节省人力、物力,具有较好的经济效益。

3. 操作可行性

操作可行性指系统的操作方式在用户组织中是否行得通。餐饮管理系统的功能较为简单,页面简单明了,没有那些繁琐的、不必要的操作。用户一看就能够知道应该怎么进行操作。管理员的界面也较为简单,都是些基本的操作,员工可以很快掌握,在操作方面也很容易实现。

(二)功能需求分析

餐饮管理系统是对餐饮流程的数字化的管理,既可以帮助餐厅更好地管理职员信息,又方便了顾客消费,并且不同的用户使用权限不同。具体功能有:用户的登录、基本信息、点/加菜、账单查询、结账、辅助功能、系统维护、系统设置等。

用户登录:用户选择自己的身份(超级管理员、经理、顾客)登录,若身份选择错误,则登不上。用户根据自己的账号、密码及正确的身份登录到系统主界面。

职员信息:超级管理员及经理有权限管理职员的基本信息。职员信息功能模块包括总体职员的查询、职员信息的添加、职员信息的修改以及职员信息的删除。

桌台信息:超级管理员及经理有权限管理桌台的基本信息。桌台信息功能模块包括桌台的查询、桌台信息的添加、桌台信息的修改及桌台信息的删除。

点/加菜:该功能实现顾客点菜及加菜。

账单查询:顾客可根据自己的消费情况,查询自己的账单。

结账:根据该桌台的消费情况及包间费,汇总出总价,并可计算实收与找零。

辅助功能:作为一个系统,应该具备一些辅助的功能,如日历及计算器。

系统维护:只有超级管理员才有这样的权限,可实现权限管理、系统备份、系统恢复。

系统设置:包括系统的口令设置及锁定系统。

三、系统设计与实现

系统模块主要包括五个主要模块:基本信息模块、桌台操作模块、系统设置模块、辅助工具模块、退出模块。其中基本信息模块又分两个子模块:桌台基本信息和职员基本信息。桌台操作是本系统主要的功能,它包括对桌台实行开台、点菜的操作,同时针对某一个桌台可以进行消费查询及结账。系统设置模块主要包括口令设置和锁定系统,该模块主要是对系统的安全性的一个保障,也是本系统不可缺少的一部分。作为一个系统应该需要有一些辅助工具,如日历、计算器、记事本,所以该系统有一个辅助工具模块。一个完整的系统肯定有退出模块,即退出系统。

餐饮管理系统中主要功能的详细设计如下。

(一)登录模块设计

登录模块以登录的用户名、密码和用户权限作为搜索条件,在数据库中进行查询。单击登录按钮时,登录模块首先判断是否输入了用户名和密码,如果没有输入用户名和密码将弹出提示框,提示用户输入登录系统的用户名和密码;如果输入了用户名和密码,系统将判断用户名、密码和权限是否匹配。若匹配,则登录成功。

(二)主界面模块设计

成功登录后,会显示主界面,主界面中应该包括菜单栏、桌台显示和显示系统状态栏。在窗体加载时,首先判断登录用户的权限,根据用户登录的权限,分配不同的功能。当窗体焦点触发时,系统从数据库中检索出所有桌台的状态信息,然后调用自定义的AddItem方法添加桌台。用户点击某个桌台时,系统会根据该桌台当前的状态,弹出不同的右键菜单。

(三)开台模块设计

开台窗体中应该有桌台信息和职员信息及用餐人数,窗体加载时,将数据库中的所有的桌台信息和职员信息检索出来显示在ComboBox控件上。应在用餐人数文本框中输入用餐人数,并且用餐人数应是大于0的整数数字,保存后即对桌台进行开台操作。

(四)点菜模块设计

点菜模块可利用TreeView控件来显示所有的菜系,利用DataGridView控件显示顾客消费的所有信息。设计该模块时通过数据库中检索出所有的菜系名称显示到TreeView中,用户选择菜系后,应设计一个存储这些被选择的菜系的数据表,并在该模块中能显示出来,以便使误点的菜可以删除。

(五)结账模块设计

结账模块中,可在数据库中检索出顾客消费的所有项目,应有菜系的消费和包间的消费,根据两者的消费,显示出总的消费。顾客输入金额时,系统可自动找零,并显示到界面上。

(六)桌台基本信息模块设计

桌台基本信息应该具有对于桌台添加、删除、修改、查询等操作。添加桌台信息时,在数据库中检索桌台信息的数据表,并将信息添加到信息表中。查询桌台信息时,系统连接数据库,在数据库中检索到数据库的数据表,并将桌台信息显示到界面上。

四、小结

小型实体店餐饮管理系统是在.net平台上进行,结合后端的SQL Server 2000数据库技术,完成了桌台的管理、职员的管理、顾客开台,点菜/加菜、账目查询及消费账目结算等功能。系统信息查询灵活又方便、数据存储安全可靠、成本低。另外系统自身有如下优点。

一是使用较方便,用户上手快。

二是系统自动结账,结账速度快速且准确。

三是系统为提高客户服务质量提供了有效的技术保证。

通过小型实体店餐饮管理系统能能够切实有效地指导工作人员规范业务操作流程,更高效、快捷地实现业务的管理,保障顾客信息的安全,提高管理水平和工作效率,进而提高业务竞争能力。

餐饮管理系统设计论文文献

[1]吕品,陈凤培.某中小型餐饮店管理信息系统的设计与开发[J].桂林航天工业高等专科学校学报,2011(04).

[2]崔海龙,李允.电子商务在餐饮业中的运用[J].管理观察,2009(18).

[3]余伟,赵亮.基于SOA的银行中间交易平台的设计与架构[J].科技广场,2011(07).

餐饮管理系统设计论文篇二

餐饮管理系统中数据完整性的设计

餐饮管理系统设计论文摘要

摘 要: 以餐饮管理系统数据库中部分表为例,详细介绍个人对数据完整性设计思路和设计方法,通过实例阐述数据完整性在实践中的应用,并给出基于SQLSERVERDE语言的描述。

餐饮管理系统设计论文内容

关键词: 数据库;数据完整性;约束;触发器

中图分类号:TP311 文献标识码:A 文章 编号:1671-7597(2011)1210173-01

数据库的创建是一件非常容易的事情,但是设计一个严谨、安全、可靠的数据库就不那么容易了,它需要你有扎实的理论知识做基础,还需要具备一定的分析问题解决问题的能力。数据库的设计经过需求分析、数据库概念机构设计、逻辑结构设计之后我们就应考虑数据完整性的设计了。数据完整性是最大限度的保证数据的正确性、可靠性、一致性。数据完整性包含三个方面的内容即实体完整性、参照完整性(引用完整性)和用户自定义完整性(域完整性)。

下面以餐饮管理系统部分可以实现点菜和结账的表为例阐述以上完整性的设计。餐饮管理涉及的表的关系模式为:桌台表zt(桌号zh,桌名zm,容纳人数rnrs,状态zt,类型lx),菜单表cd(菜品编号cpbh,菜品名称cpmc,规格gg,类别lb,单价dj,成本价cbj),订单表dd(订单编号ddbh,订单日期ddrq,桌号zh,消费金额xfje),点菜表dc(订单编号ddbh,菜品编号cpbh,数量sl)。以上四个表的定义如下:

Create table zt (zh char(4) primary key ,zm char(8) unique, rnrs int check (rnrs>=0),zt bit,lx char(8) check (lx='大厅' or lx='包厢' lx='vip'))

Create table cd(cpbh char(5) primary key, cpmc char(12),gg char(10),lb char(8),dj numeric(6,1) check(dj>=0),cbj numeric(6,1) check(cbj>=0))

Create table dd (ddbh char(10) primary key,ddrq datetime,zh char(4) foreign key references zt(zh), xfje numeric(10,1))

Create table dc (ddbh char(10) foreign key references dd(ddbh),cpbh char(5) foreign key references cd(cpbh),sl int check(sl>=0) default 1,primary key(ddbh,cpbh))

1 实体完整性(表完整性)

实体完整性又叫做表完整性,是对表中主键的约束。实体完整性的规则要求:在任何关系的任何一个元组中,主键的值不能为空值、也不能取重复的值。建立实体完整性的目的是用于保证数据库表中的每一个元组都是惟一的。是否可以改变主键值或删除一整行,取决于主键和其他表之间要求的完整性级别。实体完整性的定义比较简单。实现“实体完整性”的方法有primary key约束、unique约束、标识列、惟一索引。在此对桌台表zt中的桌号zh、菜单表cd表中的菜品编号cpbh以及订单表dd中的订单编号ddbh定义了primary key约束。在定义的时候一定要注意,一张完整的表定义只能有一个主键(PRIMARY KEY),但是可以没有UNIQUE约束。

2 参照完整性规则(引用完整性规则)

现实世界中的实体之间存在某种联系。在关系模型中实体及实体间的联系都是用关系来描述的,这样就自然存在着关系与关系间的引用。通过在同一个数据库的两个表中进行主键约束和外键约束来实现,参照的列和被参照的列的必须具有相同的属性。

参照完整性规则规则要求:“不引用不存在的实体”。即:不允许在一个关系中引用另一个关系中不存在的元组。其目的用于确保相关联的表间的数据保持一致。参照完整性是对外键的约束,要求外键的取值只能为两种情况:若取非空值,则它必须是主表中存在的值。要么取空值(null)。设置了参照完整性禁止在从表中插入包含主表中不存在的关键字的数据行;禁止删除在从表中的有对应记录的主表记录。

在如上四个表中对订单表dd的桌号zh、点菜表对此dc的订单编号ddbh及菜品编号cpbh分别设置了外键。另外外键的设计也可由触发器或编程语言来设定。以订单表dd为例触发器设置方法如下:

CREATE TRIGGER insert_xs ON dd

AFTER INSERT

AS

IF EXISTS

(SELECT * FROM INSERTED

WHERE zh IN (SELECT zh FROM zt))

PRINT '添加成功!’

ELSE

BEGIN

PRINT '桌号与存在的桌号不符!’

ROLLBACK TRANSACTION

END

同样可以对点菜表设置一个触发器要求dc的订单编号ddbh及菜品编号cpbh也具有参照性。参照完整性是用来维护相关数据表之间数据一致性的手段,通过实现引用完整性,可以避免因一个数据表的记录改变而使另一个数据表内的数据变成无效的值。

3 域完整性

域完整性也称为列完整性或用户定义的完整性,用于限制用户向列中输入的内容。域完整性规则要求由用户根据实际情况,定义表中属性的取值范围。其目的用于保证给定字段中数据的有效性,即保证数据的取值在有效的范围内。

设置域完整性的方法是限制列的数据类型、精度、范围、格式和长度等。可以通过指定数据类型、CHECK约束、DEFAULT约束、NOT NULL约束和创建规则、默认值等数据库对象来实施。

数据库中存储的数据多种多样,为每一列指定一个准确的数据类型是设计表的第一步,列的数据类型规定了列上允许的数据值。当添加或修改数据时,其类型必须要符合建表时所指定的数据类型。这种方式为数据库中的数据完整性提供了最基本的保障。

约束是SQL Server提供的自动保持数据完整性的一种方法,是独立于表结构的。规则是实现域完整性的方法之一,用来验证一个数据库中的数据是否处于一个指定的值域范围内,是否与特定的格式相匹配。当数据库中的数据值被更新或插入时,就要检查新值是否遵循规则。如果不符合规则就拒绝执行更新或插入操作。

在餐饮系统相关表中我们对相应的列设置了数据类型及长度度限制,并对菜单表cd的单价dj设置了check(dj>=0)的约束,对点菜表dc的数量sl列(sl int check(sl>=0) default 1)设置了check约束和默认值的约束。当然对于以上约束我们都可通过定义规则的方法实现。如:

用create rule dyl as@x>=0来定义一个大于零的约束,然后用sp_bindrule dyl,'cd.dj‘语句和sp_bindrule dyl,'dc.sl'语句将其绑定到菜单表cd的单价dj列及点菜表dc的数量sl列上。

对于菜品编号cpbh我们规定菜类必须以类别的代表字母作为第一个字符,小分类的代表字母为第二个字符后面跟3位数字来表示。如CL001表示青菜类、LN001可表示奶类饮料。类别分类如表1:

表1 菜单类别表

为了实现上述编码我们用规则来实现如下:

Create rule cpbm as

@BM like 'C[LQRT][0-9][0-9][0-9]'

Or @BM like 'J[PBNM][0-9][0-9][0-9]'

Or @BM like 'Y[CNGT][0-9][0-9][0-9]'

Or @BM like 'z[fm][0-9][0-9][0-9]'

sp_bindrule cpbm, 'cd.cpbh'

4 触发器实现数据完整性

当用户对数据的完整性要求更为特殊,更为复杂,以上3种完整性就无法满足用户的要求。在这种情况下,用户需要自己定义所需的完整性。实现自定义完整性的重要方法是创建触发器。触发器是一种数据库对象。是一种表或视图执行insert、delete、update操作时,被系统自动执行的特殊的存储过程。创建触发器的目的是对表实现复杂的数据完整性约束,以防止不正确的操作。它与数据库中的某个表的数据修改操作相关联,修改操作可以是INSERT、UPDATE、和DELETE这3种操作中其中一种或几种。当用户对相关表执行触发器相关的修改操作时触发器自动执行。常用于数据的参照完整性限制及级联删除、级联更新等操作的设置。以级联更新为例,分析当菜单表中的菜品编号修改时,点菜表中的菜品编号同时更新这样的操作用触发器如何实现:

create trigger upd on cd after update

as

declare @jbh char(5),@xbh char(5)

select @jbh=deleted.cpbh, @xbh= inserted.cpbh

from deleted,inserted where deleted.cpbh=inserted.cpbh

print '准备级联更新点菜表中的菜品编号信息….'

update dc set cpbh=@xbh where cpbh=@jbh

print '已经级联更新了点菜表原菜品编号为'+ @jbh +'的信息'

5 应用接口编程

应用接口编程对数据库应用设计来说是负担最重的方法,但同时又是最基本、最灵活的方法。不论数据库管理系统提供了多么丰富的完整性的约束手段,利用编程接口保证数据完整性仍是所有数据库应用设计者必须掌握的关键技术之一。

6 总结

保证数据库的数据完整性,在数据库管理系统中是十分重要的。合理地使用SQL Server为数据完整性提供的各项 措施 ,对数据进行所需的约束限制,可以有效降低数据库在使用过程中可能出现的错误,提高数据库系统的可用性,减少处理数据错误所耗的费用。

餐饮管理系统设计论文文献

[1]陈伟,Sql Server2005应用系统开发教程[M].北京:清华大学出版社.

[2]Andrew J.Brust Stephen Forte着,精通SQLServer 2005程序设计,贾洪峰译,清华大学出版社,2007.

[3]萨师煊、王珊,数据库系统概论(第三版)[M].北京:高等 教育 出版社,2004.

有关餐饮管理系统设计论文推荐:

1. 浅谈餐饮服务与管理论文

2. 高档餐饮服务管理研究毕业论文

3. 酒店管理系统毕业论文

4. 有关餐饮服务与管理论文

5. 学生管理系统论文

6. 学籍管理系统毕业设计论文

③ 哲学家就餐问题的算法实现

操作系统并发和互斥:哲学家进餐问题和理发师问题

1. 哲学家进餐问题:
(1) 在什么情况下5 个哲学家全部吃不上饭?
考虑两种实现的方式,如下:
A.
算法描述:
void philosopher(int i) /*i:哲学家编号,从0 到4*/
{
while (TRUE) {
think( ); /*哲学家正在思考*/
take_fork(i); /*取左侧的筷子*/
take_fork((i+1) % N); /*取左侧筷子;%为取模运算*/
eat( ); /*吃饭*/
put_fork(i); /*把左侧筷子放回桌子*/
put_fork((i+1) % N); /*把右侧筷子放回桌子*/
}
}
分析:假如所有的哲学家都同时拿起左侧筷子,看到右侧筷子不可用,又都放下左侧筷子,
等一会儿,又同时拿起左侧筷子,如此这般,永远重复。对于这种情况,即所有的程序都在
无限期地运行,但是都无法取得任何进展,即出现饥饿,所有哲学家都吃不上饭。
B.
算法描述:
规定在拿到左侧的筷子后,先检查右面的筷子是否可用。如果不可用,则先放下左侧筷子,
等一段时间再重复整个过程。
分析:当出现以下情形,在某一个瞬间,所有的哲学家都同时启动这个算法,拿起左侧的筷
子,而看到右侧筷子不可用,又都放下左侧筷子,等一会儿,又同时拿起左侧筷子……如此
这样永远重复下去。对于这种情况,所有的程序都在运行,但却无法取得进展,即出现饥饿,
所有的哲学家都吃不上饭。
(2) 描述一种没有人饿死(永远拿不到筷子)算法。
考虑了四种实现的方式(A、B、C、D):
A.原理:至多只允许四个哲学家同时进餐,以保证至少有一个哲学家能够进餐,最终总会释
放出他所使用过的两支筷子,从而可使更多的哲学家进餐。以下将room 作为信号量,只允
许4 个哲学家同时进入餐厅就餐,这样就能保证至少有一个哲学家可以就餐,而申请进入
餐厅的哲学家进入room 的等待队列,根据FIFO 的原则,总会进入到餐厅就餐,因此不会
出现饿死和死锁的现象。
伪码:
semaphore chopstick[5]={1,1,1,1,1};
semaphore room=4;
void philosopher(int i)
{
while(true)
{
think();
wait(room); //请求进入房间进餐
wait(chopstick[i]); //请求左手边的筷子
wait(chopstick[(i+1)%5]); //请求右手边的筷子
eat();
signal(chopstick[(i+1)%5]); //释放右手边的筷子
signal(chopstick[i]); //释放左手边的筷子
signal(room); //退出房间释放信号量room
}
}
B.原理:仅当哲学家的左右两支筷子都可用时,才允许他拿起筷子进餐。
方法1:利用AND 型信号量机制实现:根据课程讲述,在一个原语中,将一段代码同时需
要的多个临界资源,要么全部分配给它,要么一个都不分配,因此不会出现死锁的情形。当
某些资源不够时阻塞调用进程;由于等待队列的存在,使得对资源的请求满足FIFO 的要求,
因此不会出现饥饿的情形。
伪码:
semaphore chopstick[5]={1,1,1,1,1};
void philosopher(int I)
{
while(true)
{
think();
Swait(chopstick[(I+1)]%5,chopstick[I]);
eat();
Ssignal(chopstick[(I+1)]%5,chopstick[I]);
}
}
方法2:利用信号量的保护机制实现。通过信号量mutex对eat()之前的取左侧和右侧筷
子的操作进行保护,使之成为一个原子操作,这样可以防止死锁的出现。
伪码:
semaphore mutex = 1 ;
semaphore chopstick[5]={1,1,1,1,1};
void philosopher(int I)
{
while(true)
{
think();
wait(mutex);
wait(chopstick[(I+1)]%5);
wait(chopstick[I]);
signal(mutex);
eat();
signal(chopstick[(I+1)]%5);
signal(chopstick[I]);
}
}
C. 原理:规定奇数号的哲学家先拿起他左边的筷子,然后再去拿他右边的筷子;而偶数号
的哲学家则相反.按此规定,将是1,2号哲学家竞争1号筷子,3,4号哲学家竞争3号筷子.即
五个哲学家都竞争奇数号筷子,获得后,再去竞争偶数号筷子,最后总会有一个哲学家能获
得两支筷子而进餐。而申请不到的哲学家进入阻塞等待队列,根FIFO原则,则先申请的哲
学家会较先可以吃饭,因此不会出现饿死的哲学家。
伪码:
semaphore chopstick[5]={1,1,1,1,1};
void philosopher(int i)
{
while(true)
{
think();
if(i%2 == 0) //偶数哲学家,先右后左。
{
wait (chopstick[ i + 1 ] mod 5) ;
wait (chopstick[ i]) ;
eat();
signal (chopstick[ i + 1 ] mod 5) ;
signal (chopstick[ i]) ;
}
Else //奇数哲学家,先左后右。
{
wait (chopstick[ i]) ;
wait (chopstick[ i + 1 ] mod 5) ;
eat();
signal (chopstick[ i]) ;
signal (chopstick[ i + 1 ] mod 5) ;
}
}
D.利用管程机制实现(最终该实现是失败的,见以下分析):
原理:不是对每只筷子设置信号量,而是对每个哲学家设置信号量。test()函数有以下作
用:
a. 如果当前处理的哲学家处于饥饿状态且两侧哲学家不在吃饭状态,则当前哲学家通过
test()函数试图进入吃饭状态。
b. 如果通过test()进入吃饭状态不成功,那么当前哲学家就在该信号量阻塞等待,直到
其他的哲学家进程通过test()将该哲学家的状态设置为EATING。
c. 当一个哲学家进程调用put_forks()放下筷子的时候,会通过test()测试它的邻居,
如果邻居处于饥饿状态,且该邻居的邻居不在吃饭状态,则该邻居进入吃饭状态。
由上所述,该算法不会出现死锁,因为一个哲学家只有在两个邻座都不在进餐时,才允
许转换到进餐状态。
该算法会出现某个哲学家适终无法吃饭的情况,即当该哲学家的左右两个哲学家交替
处在吃饭的状态的时候,则该哲学家始终无法进入吃饭的状态,因此不满足题目的要求。
但是该算法能够实现对于任意多位哲学家的情况都能获得最大的并行度,因此具有重要
的意义。
伪码:
#define N 5 /* 哲学家人数*/
#define LEFT (i-1+N)%N /* i的左邻号码 */
#define RIGHT (i+1)%N /* i的右邻号码 */
typedef enum { THINKING, HUNGRY, EATING } phil_state; /*哲学家状态*/
monitor dp /*管程*/
{
phil_state state[N];
semaphore mutex =1;
semaphore s[N]; /*每个哲学家一个信号量,初始值为0*/
void test(int i)
{
if ( state[i] == HUNGRY &&state[LEFT(i)] != EATING &&
state[RIGHT(i)] != EATING )
{
state[i] = EATING;
V(s[i]);
}
}
void get_forks(int i)
{
P(mutex);
state[i] = HUNGRY;
test(i); /*试图得到两支筷子*/
V(mutex);
P(s[i]); /*得不到筷子则阻塞*/
}
void put_forks(int i)
{
P(mutex);
state[i]= THINKING;
test(LEFT(i)); /*看左邻是否进餐*/
test(RIGHT(i)); /*看右邻是否进餐*/
V(mutex);
}
}
哲学家进程如下:
void philosopher(int process)
{
while(true)
{
think();
get_forks(process);
eat();
put_forks(process);
}
}
2.理发师问题:一个理发店有一个入口和一个出口。理发店内有一个可站5 位顾客的站席
区、4 个单人沙发、3 个理发师及其专用理发工具、一个收银台。新来的顾客坐在沙发上等
待;没有空沙发时,可在站席区等待;站席区满时,只能在入口外等待。理发师可从事理
发、收银和休息三种活动。理发店的活动满足下列条件:
1)休息的理发师是坐地自己专用的理发椅上,不会占用顾客的沙发;
2)处理休息状态的理发师可为在沙发上等待时间最长的顾客理发;
3)理发时间长短由理发师决定;
4)在站席区等待时间最长的顾客可坐到空闲的理发上;
5)任何时刻最多只能有一个理发师在收银。
试用信号量机制或管程机制实现理发师进程和顾客进程。
原理:
(1)customer 进程:
首先检查站席区是否已满(stand_capacity),若满选择离开,否则进入站席区,即进入
理发店。在站席区等待沙发的空位(信号量sofa),如果沙发已满,则进入阻塞等待队列,
直到出现空位,在站席区中等待时间最长的顾客离开站席区(stand_capacity)。坐到沙
发上,等待理发椅(barber_chair),如果理发椅已满,则进入阻塞等待队列,直到出现
空位,在沙发上等待时间最长的顾客离开沙发(释放信号量sofa)。坐到理发椅上,释放
准备好的信号(customer_ready),获得该理发师的编号(0~1 的数字)。等待理发师理
发结束(finished[barber_number])。在离开理发椅之前付款(payment),等待收据
(receipt),离开理发椅(leave_barberchair)。最后离开理发店。
这里需要注意几点:
a) 首先是几个需要进行互斥处理的地方,主要包括:进入站席区、进入沙发、进入理发椅
和付款几个地方。
b) 通过barber_chair 保证一个理发椅上最多只有一名顾客。但这也不够,因为单凭
baber_chair 无法保证一名顾客离开理发椅之前,另一位顾客不会坐到该理发椅上,
因此增加信号量leave_barberchair,让顾客离开理发椅后,释放该信号,而理发
师接收到该信号后才释放barber_chair 等待下一位顾客。
c) 在理发的过程中,需要保证是自己理发完毕,才能够进行下面的付款、离开理发椅的活
动。这个机制是通过customer 进程获得给他理发的理发师编号来实现的,这样,当
该编号的理发师释放对应的finished[i]信号的时候,该顾客才理发完毕。
d) 理发师是通过mutex 信号量保证他们每个人同时只进行一项操作(理发或者收款)。
e) 为了保证该顾客理发完毕后马上可以付款离开,就应该保证给该顾客理发的理发师在理
发完毕后马上到收银台进入收款操作而不是给下一位顾客服务。在伪码中由以下机制实
现:即顾客在释放离开理发椅的信号前,发出付款的信号。这样该理发师得不到顾客的
离开理发椅的信号,不能进入下一个循环为下一名顾客服务,而只能进入收款台的收款
操作。直到顾客接到收据后,才释放离开理发椅的信号,离开理发椅,让理发师释放该
理发椅的信号,让下一位等待的顾客坐到理发椅上。
(2)barber 进程
首先将该理发师的编号压入队列,供顾客提取。等待顾客坐到理发椅坐好(信号量
customer_ready),开始理发,理发结束后释放结束信号(finished[i])。等待顾客
离开理发椅(leave_barberchair)(期间去收银台进行收款活动),释放理发椅空闲信
号(barber_chair),等待下一位顾客坐上来。
(3)cash(收银台)进程
等待顾客付款(payment),执行收款操作,收款操作结束,给付收据(receipt)。
信号量总表:
信号量 wait signal
stand_capacity 顾客等待进入理发店 顾客离开站席区
sofa 顾客等待坐到沙发 顾客离开沙发
barber_chair 顾客等待空理发椅 理发师释放空理发椅
customer_ready 理发师等待,直到一个顾客坐
到理发椅
顾客坐到理发椅上,给理发师
发出信号
mutex 等待理发师空闲,执行理发或
收款操作
理发师执行理发或收款结束,
进入空闲状态
mutex1 执行入队或出队等待 入队或出队结束,释放信号
finished[i] 顾客等待对应编号理发师理
发结束
理发师理发结束,释放信号
leave_barberchair 理发师等待顾客离开理发椅 顾客付款完毕得到收据,离开
理发椅释放信号
payment 收银员等待顾客付款 顾客付款,发出信号
receipt 顾客等待收银员收、开具收据收银员收款结束、开具收据,
释放信号
伪码:
semaphore stand_capacity=5;
semaphore sofa=4;
semaphore barber_chair=3;
semaphore customer_ready=0;
semaphore mutex=3;
semaphore mutex1=1;
semaphore finished[3]={0,0,0};
semaphore leave_barberchair=0;
semaphore payment=0;
semaphore receipt=0;
void customer()
{
int barber_number;
wait(stand_capacity); //等待进入理发店
enter_room(); //进入理发店
wait(sofa); //等待沙发
leave_stand_section(); //离开站席区
signal(stand_capacity);
sit_on_sofa(); //坐在沙发上
wait(barber_chair); //等待理发椅
get_up_sofa(); //离开沙发
signal(sofa);
wait(mutex1);
sit_on_barberchair(); //坐到理发椅上
signal(customer_ready);
barber_number=dequeue(); //得到理发师编号
signal(mutex1);
wait(finished[barber_number]); //等待理发结束
pay(); //付款
signal(payment); //付款
wait(receipt); //等待收据
get_up_barberchair(); //离开理发椅
signal(leave_barberchair); //发出离开理发椅信号
exit_shop(); //了离开理发店
}
void barber(int i)
{
while(true)
{
wait(mutex1);
enqueue(i); //将该理发师的编号加入队列
signal(mutex1);
wait(customer_ready); //等待顾客准备好
wait(mutex);
cut_hair(); //理发
signal(mutex);
signal(finished[i]); //理发结束
wait(leave_barberchair); //等待顾客离开理发椅信号
signal(barber_chair); //释放barber_chair 信号
}
}
void cash() //收银
{
while(true)
{
wait(payment); //等待顾客付款
wait(mutex); //原子操作
get_pay(); //接受付款
give_receipt(); //给顾客收据
signal(mutex);
signal(receipt); //收银完毕,释放信号
}
}
分析:
在分析该问题过程中,出现若干问题,是参阅相关资料后才认识到这些问题的隐蔽性和严重
性的,主要包括:
(1)在顾客进程,如果是在释放leave_barberchair 信号之后进行付款动作的话,很
容易造成没有收银员为其收款的情形, 原因是: 为该顾客理发的理发师收到
leave_barberchair 信号后,释放barber_chair 信号,另外一名顾客坐到理发椅上,
该理发师有可能为这另外一名顾客理发,而没有为刚理完发的顾客收款。为解决这个问题,
就是采取在释放leave_barberchair 信号之前,完成付款操作。这样该理发师无法进入
下一轮循环为另外顾客服务,只能到收银台收款。
(2)本算法是通过给理发师编号的方式,当顾客坐到某理发椅上也同时获得理发师的编号,
如此,当该理发师理发结束,释放信号,顾客只有接收到为其理发的理发师的理发结束信号
才会进行付款等操作。这样实现,是为避免这样的错误,即:如果仅用一个finished 信
号量的话,很容易出现别的理发师理发完毕释放了finished 信号,把正在理发的这位顾
客赶去付款,而已经理完发的顾客却被阻塞在理发椅上的情形。当然也可以为顾客进行编
号,让理发师获取他理发的顾客的编号,但这样就会限制顾客的数量,因为finished[]
数组不能是无限的。而为理发师编号,则只需要三个元素即可。
3.参考文献:
左金平 计算机操作系统中哲学家进餐问题探究。
参考教材 操作系统—内核与设计原理

热点内容
安卓手机如何打开桌面与快捷方式 发布:2024-09-23 02:36:01 浏览:497
linux查找find 发布:2024-09-23 02:36:00 浏览:440
linuxgcc编译命令行 发布:2024-09-23 02:35:59 浏览:520
什么是java锁 发布:2024-09-23 02:22:29 浏览:383
手游服务器搭建教程失败 发布:2024-09-23 02:00:21 浏览:687
短暂的访问 发布:2024-09-23 01:29:08 浏览:828
安卓手机怎么设置4位数 发布:2024-09-23 01:24:58 浏览:548
5g和算法 发布:2024-09-23 01:20:40 浏览:508
pandas开发程序编译 发布:2024-09-23 01:13:58 浏览:467
android应用被系统回收 发布:2024-09-23 01:10:36 浏览:448