【操作系统】信号量解决经典同步问题
文章目錄
- 1. 基本結(jié)構(gòu)
- 2. P,V操作
- 3. 信號(hào)量的應(yīng)用
- 3.1 信號(hào)量實(shí)現(xiàn)進(jìn)程互斥
- 3.2 信號(hào)量實(shí)現(xiàn)前驅(qū)關(guān)系
- 4. 用信號(hào)量解經(jīng)典同步問題
- 4.1 生產(chǎn)者消費(fèi)者問題
- 4.2 讀者寫者問題
- 4.3 狒狒過橋問題
- 4.4 理發(fā)師理發(fā)問題
- 4.5 哲學(xué)家進(jìn)餐問題
信號(hào)量機(jī)制是Dijkstra提出的一種卓有成效的進(jìn)程同步工具。信號(hào)量有整形信號(hào)量、記錄型信號(hào)量、AND型信號(hào)量等,這里主要介紹我們常見的記錄型信號(hào)量。
1. 基本結(jié)構(gòu)
typedef struct {int value; //信號(hào)量值struct process_cntrol_block *list; //阻塞隊(duì)列 }semaphore;在應(yīng)用信號(hào)量的時(shí)候,信號(hào)量的值往往是臨界資源的數(shù)量。當(dāng)臨界資源數(shù)量不足時(shí),新的進(jìn)程就阻塞,并插入到信號(hào)量阻塞隊(duì)列中。
2. P,V操作
wait(S)和signal(S)操作是信號(hào)量機(jī)制的基本操作(通常稱作P,V操作),定義如下:
wait(semaphore *S) {S->value--; //信號(hào)量的值減一if(S->value < 0) block(S->list); //如果信號(hào)量的值小于零,進(jìn)程阻塞signal(semaphore *S) {S->value++; //信號(hào)量的值加一if(S->value <= 0) wakeup(S->list); //喚醒 }在實(shí)現(xiàn)進(jìn)程同步時(shí),一般先將S->value的初值設(shè)定為臨界資源的初始數(shù)量,一旦進(jìn)程要請(qǐng)求一個(gè)臨界資源,先對(duì)代表此進(jìn)程的信號(hào)量執(zhí)行P操作,也就意味著資源數(shù)減一,當(dāng)該進(jìn)程運(yùn)行完畢時(shí),執(zhí)行V操作,意味著資源數(shù)加一。值得注意的是,如果當(dāng)前資源數(shù)量為0,再有進(jìn)程想請(qǐng)求臨界資源,就會(huì)在執(zhí)行P操作時(shí)進(jìn)入阻塞隊(duì)列,信號(hào)量值變?yōu)?1,此后執(zhí)行P操作的進(jìn)程也都會(huì)被阻塞,信號(hào)量的絕對(duì)值為阻塞的進(jìn)程數(shù)目。
3. 信號(hào)量的應(yīng)用
3.1 信號(hào)量實(shí)現(xiàn)進(jìn)程互斥
有了P,V操作,我們就能很簡(jiǎn)單的實(shí)現(xiàn)進(jìn)程互斥。方法是:設(shè)mutex為互斥信號(hào)量,初值為1。在需要互斥的臨界區(qū)前后分別使用P,V操作即可,示意代碼如下:
semaphore mutex = 1; //一般初值為1的信號(hào)量用來實(shí)現(xiàn)互斥 P_A() { //進(jìn)程Awhile(1) {P(mutex);臨界區(qū);V(mutex);剩余區(qū);} } P_B() { //進(jìn)程Bwhile(1) {P(mutex);臨界區(qū);V(mutex);剩余區(qū);} }在互斥問題中,我們可以把P操作理解成“上鎖”,把V操作理解成“解鎖”,當(dāng)P_A和P_B兩個(gè)進(jìn)程并發(fā)執(zhí)行時(shí),無論哪一個(gè)進(jìn)程先執(zhí)行到了P操作,都會(huì)接下來執(zhí)行P操作的進(jìn)程阻塞,直到前一個(gè)進(jìn)程執(zhí)行到了V操作為止,這樣就實(shí)現(xiàn)了臨界區(qū)的互斥。
3.2 信號(hào)量實(shí)現(xiàn)前驅(qū)關(guān)系
思路如下:為每一組想要實(shí)現(xiàn)前后關(guān)系的進(jìn)程,都分別定義一個(gè)信號(hào)量,初值設(shè)為0,把你想要先執(zhí)行的進(jìn)程后面加一個(gè)V操作,想要后執(zhí)行的進(jìn)程前面加一個(gè)P操作。這樣一來,你想要后執(zhí)行的進(jìn)程如果先執(zhí)行了,就會(huì)因?yàn)閳?zhí)行了其前面的P操作而阻塞,直到你想要先執(zhí)行的進(jìn)程執(zhí)行完了,執(zhí)行V操作后,才能解除阻塞繼續(xù)執(zhí)行。以上就是用信號(hào)量實(shí)現(xiàn)前驅(qū)關(guān)系的過程。
假如我們要實(shí)現(xiàn)四個(gè)語句S1,S2,S3,S4需要按照一定的順序同步執(zhí)行,比如S1執(zhí)行完S2,S3才能執(zhí)行,S2,S3執(zhí)行完了S4才能執(zhí)行,代碼如下:
4. 用信號(hào)量解經(jīng)典同步問題
4.1 生產(chǎn)者消費(fèi)者問題
假定生產(chǎn)者和消費(fèi)者之間的公用緩沖池有n個(gè)緩沖區(qū),生產(chǎn)者可以向緩沖區(qū)生產(chǎn)一個(gè)產(chǎn)品,消費(fèi)者可以從緩沖區(qū)消耗一個(gè)產(chǎn)品,注意:生產(chǎn)者不能同時(shí)生產(chǎn),消費(fèi)者也不能同時(shí)消費(fèi),也不能同時(shí)生產(chǎn)和消費(fèi),當(dāng)緩沖區(qū)空時(shí)無法消費(fèi),當(dāng)緩沖區(qū)滿時(shí)無法生產(chǎn)。請(qǐng)用信號(hào)量機(jī)制解決這一問題。
解法如下:
4.2 讀者寫者問題
假設(shè)一個(gè)文件可被多個(gè)進(jìn)程共享,我們?cè)试S多個(gè)進(jìn)程同時(shí)讀這個(gè)共享對(duì)象,但是不允許一個(gè)進(jìn)程寫這個(gè)共享對(duì)象的同時(shí),別的進(jìn)程進(jìn)行讀或?qū)憽Q句話說:讀和讀不互斥,讀和寫互斥,寫和寫互斥。請(qǐng)用信號(hào)量機(jī)制解決這一問題。
解法如下:
這個(gè)問題的程序中有個(gè)關(guān)鍵點(diǎn),就是明明讀進(jìn)程是不互斥的,為什么還需要rmutex來實(shí)現(xiàn)if判斷的互斥呢。原因如下:當(dāng)我們?cè)谶M(jìn)程互斥中使用條件語句和數(shù)值變化的時(shí)候,如果不把那一段也實(shí)現(xiàn)互斥的話,很有可能出問題,比如在這段代碼中,要是不加第5行和第8行的話:如果一個(gè)讀進(jìn)程執(zhí)行完了第6行,還沒有執(zhí)行第7行的readcount++操作之前,這個(gè)讀進(jìn)程被剝奪了處理機(jī),換另一個(gè)讀進(jìn)程上處理機(jī)運(yùn)行了,那么另一個(gè)讀進(jìn)程就會(huì)阻塞在第6行的P操作上,就無法實(shí)現(xiàn)多個(gè)讀者一起讀了;10行和13行同理,如果一個(gè)讀進(jìn)程執(zhí)行完了第11行就被剝奪處理機(jī),換上另一個(gè)讀進(jìn)程也執(zhí)行了11行,這樣readcount被連減兩次,那么這兩個(gè)進(jìn)程都能通過12行的if判斷,會(huì)執(zhí)行兩次V操作,產(chǎn)生錯(cuò)誤。
4.3 狒狒過橋問題
一個(gè)主修人類學(xué)、輔修計(jì)算機(jī)科學(xué)的學(xué)生參加了一個(gè)課題,調(diào)查非洲狒狒是否能被教會(huì)理解死鎖。他找到一處很深的峽谷,在上邊固定了一根橫跨峽谷的繩索,這樣狒狒就可以攀住繩索越過峽谷。同一時(shí)刻可以有幾只狒狒通過,只要它們朝著相同的方向。但如果向東和向西的狒狒同時(shí)攀在繩索上則將發(fā)生死鎖(狒狒將被卡在中間),因?yàn)樗鼈儫o法在吊在峽谷上時(shí)從另一只的背上翻過去。如果一只狒狒想越過峽谷,它必須看當(dāng)前是否有別的狒狒正在逆向通過。使用信號(hào)量寫一個(gè)避免死鎖的程序來解決該問題。
解法如下:
該問題屬于讀者寫者問題的改進(jìn),如果完全理解了讀者寫者問題的解法,那么這個(gè)問題也能很快解決。東狒狒之間不互斥,西狒狒之間不互斥,東西狒狒之間互斥,思路是第一個(gè)東狒狒給西狒狒上鎖,第一個(gè)西狒狒給東狒狒上鎖,注意if判斷也要實(shí)現(xiàn)互斥。
4.4 理發(fā)師理發(fā)問題
理發(fā)店里有一位理發(fā)師、一把理發(fā)椅和n把供等候理發(fā)的顧客坐的椅子。如果沒有顧客,則理發(fā)師便在理發(fā)椅上睡覺。當(dāng)一個(gè)顧客到來時(shí),他必須先叫醒理發(fā)師,如果理發(fā)師正在理發(fā)時(shí)又有顧客來到,則如果有空椅子可坐,他們就坐下來等。如果沒有空椅子,他就離開。這里的問題是為理發(fā)師和顧客各編寫一段程序來描述他們的行為,要求不能帶有競(jìng)爭(zhēng)條件。
解法如下:
這道題本身不難,但其中很多細(xì)節(jié)的實(shí)現(xiàn)需要實(shí)現(xiàn),比如座位是有上限的,這樣就不得不設(shè)置判斷條件和計(jì)數(shù),來使超過N個(gè)的顧客離開,而加入計(jì)數(shù)和判斷條件后就又要實(shí)現(xiàn)其互斥,增加了問題的復(fù)雜性。
4.5 哲學(xué)家進(jìn)餐問題
五個(gè)哲學(xué)家共用一張圓桌,分別坐在周圍的五張椅子上,在桌子上有五只碗和五只筷子,他們的生活方式是交替地進(jìn)行思考和進(jìn)餐。平時(shí),一個(gè)哲學(xué)家進(jìn)行思考,饑餓時(shí)便試圖取用其左右最靠近他的筷子,只有在他拿到兩只筷子時(shí)才能進(jìn)餐。進(jìn)餐畢,放下筷子繼續(xù)思考。請(qǐng)用信號(hào)量機(jī)制解決。
這是一個(gè)講解死鎖的時(shí)候的經(jīng)典例子,解決這道題的直接思路如下:
但是這樣可能會(huì)出現(xiàn)死鎖問題:如果所有哲學(xué)家都拿起了左手邊筷子,五個(gè)進(jìn)程就會(huì)死鎖。對(duì)于避免哲學(xué)家進(jìn)餐問題發(fā)生死鎖的方法有很多,這里只講一種:只有當(dāng)同時(shí)一個(gè)哲學(xué)家能同時(shí)拿起左右兩只筷子時(shí),才允許拿筷子,解法如下:
semaphore chopstick[5] = {1,1,1,1,1}; semaphore mutex = 1; void philosopher() {while(1) {P(mutex);P(chopstick[i]);P(chopstick[(i+1)%5]);V(mutex);吃飯;V(chopstick[i]);V(chopstick[(i+1)%5]);} }但僅僅這樣做還是有問題,如果一個(gè)哲學(xué)家獲得了兩只筷子,開始進(jìn)餐,此時(shí)他左邊或者右邊的哲學(xué)家進(jìn)入了臨界區(qū)后,被阻塞在第6行或者第7行,那么其他的哲學(xué)家就無法進(jìn)入臨界區(qū)了,也就是說這個(gè)時(shí)間只能有一個(gè)哲學(xué)家進(jìn)餐,但顯然同一時(shí)間是可以有不相鄰的兩個(gè)哲學(xué)家同時(shí)進(jìn)餐的。
對(duì)這個(gè)問題的更好解決方法可以去看Dijkstra在1965年給出的算法。
總結(jié)
以上是生活随笔為你收集整理的【操作系统】信号量解决经典同步问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 地下城堡3装备怎么重铸
- 下一篇: 用strace工具跟踪系统调用