信號量機制是一種卓有成效的進程互斥同步工具。這里只介紹記錄型信號量機制,它可以有效的解決CPU“忙等”的問題,實現(xiàn)互斥。
記錄型信號量機制的數(shù)據(jù)結(jié)構(gòu)如下(看不懂那些字母是什么其實沒有關(guān)系):
type semaphore=record value:integer; (下文傳說中的S) L: list of process;(排隊使用的進程要待的阻塞隊列) end;
這里需要注意記錄型信號量S的整形分量value的值的物理含義,表示該類資源可用的數(shù)目,也可以說是執(zhí)行P操作而不會被阻塞的進程的數(shù)目,一般為<=1,因為這里是進程互斥(但是也可以大于1),等于1時,表示該資源可用,等于0時,表示該資源正在被使用,而且沒有進程被阻塞,但是當期數(shù)值小于0時,其絕對值表示信號量S的阻塞隊列中的進程數(shù)。L表示進程的阻塞隊列。
記錄型信號機制的實現(xiàn)伴隨著P操作和V操作,P操作指的是測試,V操作指的是增加,不要問我為啥叫PV,我只能說來源于荷蘭語。一般P操作要伴隨著V操作,二者成雙成對出現(xiàn)。
那么我們來看看P操作和V操作到底是什么,那么神奇:
P的原語操作可以描述為: procedure P(var s:semaphore); begin s.value:=s.value-1;(將信號量值減1) if s.value<0 then block(s.L);(若信號量值小于0,則調(diào)用阻塞原語阻塞自己,插入到阻塞隊列中去) end;
V的原語操作可以描述為: procedure P(var s:semaphore); begin s.value:=s.value+1;(將信號量值加1) if s.value<0 then wakeup(s.L);(若信號量值小于等于0,則調(diào)用喚醒原語從阻塞隊列中喚醒一個進程)
舉個實際的栗子: 用P,V操作實現(xiàn)火車互聯(lián)網(wǎng)定票系統(tǒng)在北京,天津兩地的兩個終端售票進程發(fā)售同一班次車票的過程。 (1) 根據(jù)顧客要求找到公共數(shù)據(jù)單元 (2) P(S); (3) 把Pk的值讀到工作寄存器R1中;(進程的臨界區(qū)) (4) 根據(jù)顧客訂票數(shù)修改R1;(進程的臨界區(qū)) (5) 將R1的值寫到Pk中;(進程的臨界區(qū)) (6) V(S); (7) 售出顧客所定的票,返回;
例如北京的售票區(qū)搶先執(zhí)行并且進入自己的臨界區(qū),這時輪到天津區(qū)執(zhí)行進程,也要求進入臨界區(qū),執(zhí)行P(S),但是因為北京已經(jīng)在臨界區(qū)中,執(zhí)行完P(guān)了,此時的信號量S的值已經(jīng)從1減為0,然后因為天津售票執(zhí)行P(S),此時P(S)的值變?yōu)?1,導致自己阻塞,直到北京之行完V(S),使得S的值變?yōu)?,然后天津從阻塞隊列中喚醒,當它再次訪問公共票據(jù)單元時,數(shù)據(jù)已經(jīng)被背景改過了,然后就實現(xiàn)了互斥。
|
|