號誌概念的使用
在多進程的應用程式中,進程之間的協調關係特別嚴格。可以使用號誌來進行不同模組間的同步或互斥,而號誌一般用全域變數來實現。程式中的號誌類比現實世界中進行交通管理的交通燈,並提供進程之間同步或互斥訪問資源。下面是一個典型號誌同步程式的邏輯結構:
首先規定對訊號量s的兩種操作,P操作和V操作。下面是P(s)操作的步驟:
a.s=s-1。
b.若s>=0,則調用P(s)的進程繼續執行。
c.若s<0,則調用P(s)的進程被阻塞,並把它插入到等待訊號量s的阻塞隊列中。
V操作和P操作的過程相反,V(s)的步驟如下:
a.s=s+1。
b.若s>0,則調用V(s)的進程繼續執行。
c.若s<=0,從等待訊號量s的阻塞隊列中喚醒一個進程,然後調用V(s)的進程繼續執行。
1.用訊號量實現互斥
首先定義s為兩個進程互斥的公用訊號量(一般在PowerBuilder中定義成全域整型變數),初值為1,表明某互斥性質的操作還沒有開始。只要把需要互斥執行的操作放在P(s)和V(s)操作之間即可實現兩個互斥操作的非同步執行。例如,對進程p1和進程p2做如下安排即可實現互斥:
進程p1
進程p2
P(s)
P(s)
S1程式段
S2程式段
V(s)
V(s)
由於訊號量s的初值為1,故第一個進程p1執行P操作後訊號量為0,p1進程可以正常執行;如果這時進程p2開始執行,執行P操作後訊號量為-1,所以進程p2隻能處於等待狀態,等到進程p1執行完程式段S1,執行V操作,且訊號量變為0時,可以喚醒進程p2開始執行。所以兩個互斥的程式段S1和S2不會被同時執行,兩個進程p1和p2可以很好地協作。
例如,一個用戶端的兩個進程要互斥地檢索資料庫,首先定義全域變數:
Int gi_message = 1
在第一個視窗的相關事件中編寫下面的指令碼:
gi_message = gi_message – 1
Do While gi_message < 0
Yield()
Loop
dw_1.SetTransObject(SQLCA)
dw_1.Retrieve()
gi_message ++
在第二個視窗的相關事件中編寫完全相同的指令碼,這樣這兩個視窗就可以互斥地進行資料檢索。
2.用訊號量實現同步
訊號量s的初值為0,兩個進程之間的同步模型如下:
進程p1
進程p2
L1:P(s)
L2:V(s)
設進程p1先到達L1點,當它執行P(s)時,使s=-1,於是進程p1進入阻塞狀態並進入訊號量s的阻塞隊列;然後進程p2到達L2點,當它執行V(s)時,將s值變為0,於是喚醒進程p1,使其繼續執行。由此可見,當進程p1到達L1點時,除非進程p2已過了L2點,否則進程p1就要暫時處於等待狀態。這就是說,p1在L1點必須與進程p2同步。
例如,可以改進CloseWithReturn,使非response類型的視窗也能正常傳遞參數。關鍵在於使用訊號量讓視窗1在開啟視窗2之後進入等待狀態,直到視窗2關閉並返回參數後才繼續執行。首先定義兩個全域類型的整型變數:
Int gi_message=0 //訊號量
string gs_Return //用於參數傳遞
在視窗1的適當事件中(比如一個按鍵的Clicked事件等)編寫如下指令碼:
String ls_Return
Open(w_test) //開啟另一個視窗
gi_message = gi_message – 1 //訊號量執行P操作
Do While gi_message < 0
Yield()
Loop
ls_Return = gs_Return
MessageBox("提示",ls_Return)
在視窗w_test的“關閉”按鈕的Clicked事件中編寫如下指令碼:
gs_Return = "test"
Close(Parent)
在視窗w_test的Close事件中編寫如下指令碼:
gi_message ++ //執行V操作