c語言餐廳管理系統
① 餐廳桌台管理的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.參考文獻:
左金平 計算機操作系統中哲學家進餐問題探究。
參考教材 操作系統—內核與設計原理