日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

【操作系统】信号量解决经典同步问题

發(fā)布時(shí)間:2023/11/30 windows 62 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【操作系统】信号量解决经典同步问题 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 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í)行,代碼如下:

p1() {S1; V(a); V(b);} p2() {P(a); S2; V(c);} p3() {P(b); S3; V(d);} p4() {P(c); P(d); S4;}main() {semaphore a,b,c,d = 0;cobeginp1();p2();p3();p4();coend }

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ī)制解決這一問題。
解法如下:

semaphore mutex = 1; //實(shí)現(xiàn)生產(chǎn)與消費(fèi)、生產(chǎn)與生產(chǎn)、消費(fèi)與消費(fèi) semaphore full = 0, empty = n; //full表示已用緩沖區(qū)數(shù),empty表示空緩沖區(qū)數(shù) void producer() {while(1) {P(empty); //每次生產(chǎn)會(huì)減少一個(gè)空緩沖區(qū),如果沒有空緩存區(qū)了就阻塞P(mutex); //保證互斥生產(chǎn)一個(gè)產(chǎn)品;V(mutex); //保證互斥V(full); //每次生產(chǎn)增加一個(gè)已用緩沖區(qū)} } void consumer() {while(1) {P(full); //每次消費(fèi)會(huì)減少一個(gè)已用緩沖區(qū),如果沒有已用緩存區(qū)了就阻塞P(mutex);消耗一個(gè)產(chǎn)品;V(mutex);V(empty); //每次生產(chǎn)增加一個(gè)空緩沖區(qū)} }

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ī)制解決這一問題。
解法如下:

semaphore rmutex, wmutex = 1; //wmutex用以實(shí)現(xiàn)寫進(jìn)程與其它進(jìn)程的互斥 int readcount = 0; //記錄讀進(jìn)程的數(shù)量 void reader() {while(1) {P(rmutex); //見下文解釋if(readcount == 0) P(wmutex); //第一個(gè)讀進(jìn)程去把寫進(jìn)程上鎖readcount++; V(rmutex); //見下文解釋讀者讀;P(rmutex); //見下文解釋readcount--;if(readcount == 0) V(wmutex); //解鎖V(rmutex); //見下文解釋} } void writer() {while(1) {P(wmutex); //實(shí)現(xiàn)寫進(jìn)程與其他進(jìn)程都互斥寫者寫;V(wmutex);} }

這個(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è)避免死鎖的程序來解決該問題。
解法如下:

semaphore wmutex, emutex, mutex = 1; int wcount, ecount = 0; //分別記錄東西狒狒上繩索的個(gè)數(shù) void west_monkey {while(1) {P(wmutex); //使if語句互斥if(wcount == 0) P(mutex); //第一個(gè)西狒狒給東狒狒上鎖wcount++;V(wmutex); //使if語句互斥西狒狒過橋;P(wmutex);wcount--;if(wcount == 0) V(mutex);V(wmutex);} } void east_monkey { //和上面的一樣while(1) {P(emutex);if(ecount == 0) P(mutex);ecount++;V(emutex);西狒狒過橋;P(emutex);ecount--;if(ecount == 0) V(mutex);V(emutex);} }

該問題屬于讀者寫者問題的改進(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)條件。
解法如下:

semaphore customer, barber = 0; //一開始沒有顧客,理發(fā)師也是睡著的 semaphore mutex = 1; //互斥信號(hào)量 int empty = N; //空椅子數(shù)量為N void Barber() {while(1) {P(customer); //只有顧客進(jìn)程的V執(zhí)行后才能執(zhí)行,沒有顧客就阻塞(睡覺)P(mutex); //把數(shù)量的變化實(shí)現(xiàn)互斥,以免影響到顧客進(jìn)程的if判斷語句empty++; //椅子上的顧客起身V(barber); //有了一個(gè)理發(fā)師可以理發(fā)V(mutex);理發(fā);} } void Customer() {P(mutex);if(empty > 0) {empty--; //不管是不是第一個(gè)顧客,來了先得坐凳子上,因?yàn)槔戆l(fā)師在理發(fā)椅上睡覺呢V(customer); //增加一個(gè)顧客,喚醒沉睡的理發(fā)師V(mutex); P(barber); //消耗一個(gè)理發(fā)師,沒有理發(fā)師就阻塞理發(fā);} else {V(mutex);離開;} }

這道題本身不難,但其中很多細(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)典例子,解決這道題的直接思路如下:

semaphore chopstick[5] = {1,1,1,1,1}; void philosopher() {while(1) {/*當(dāng)哲學(xué)家饑餓時(shí),總是先拿左邊的筷子,再拿右邊的筷子*/P(chopstick[i]);P(chopstick[(i+1)%5]);吃飯;V(chopstick[i]);V(chopstick[(i+1)%5]);} }

但是這樣可能會(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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。