用Semaphore檢測運行實例的個數
發表于:2007-07-14來源:作者:點擊數:
標簽:
在 VB 中人們一般用App.PrevInstance檢查是否有某個程序的實例已經在運行,如果返回值是True,就表明前面至少已經有一個實例在運行。但是這種方法無法確切知道究竟有多少個實例在運行,因此,只能用它來限制某一時刻只能有一個實例在運行的情況。 分析問題
在
VB中人們一般用App.PrevInstance檢查是否有某個程序的實例已經在運行,如果返回值是True,就表明前面至少已經有一個實例在運行。但是這種方法無法確切知道究竟有多少個實例在運行,因此,只能用它來限制某一時刻只能有一個實例在運行的情況。
分析問題
對于限制運行指定個數實例的處理方法,傳統上一般通過使用FindWindow()方法來查找相同標題的窗口或窗口類來實現。但是這種方法存在一定
缺陷,一方面有些程序在運行過程中有時會改變標題;另一方面其他程序也可以輕易地用SetWindowText()來改變某個窗口的標題。所以這種方法準確率不高。
本文介紹一種方法可以克服這種缺點,基本思路是讓程序的第一個實例啟動時在一個公共的地方建立一個公共計數器,并且賦起始值,以后每次程序啟動時,讀該計數器取得已經運行的程序實例個數,并且比較是否已經達到需要限制的最大值,如果不是則繼續加載該程序并使計數器加1,否則終止加載并退出,同時,正常加載的程序在退出時還要使計數器減1以釋放資源。
由于Win32使用新的地址映射機制,使得它的的進程地址空間不像Win16那樣是連續的,而且進程通常也不可以訪問其他進程的地址空間(除非通過特殊方法)。為此,就需要用到Win32的IPC機制,該機制是Win32專門用于進程間通信的方法,它特別定義了幾個內部對象。Semaphore對象就是其中的一種資源對象,它在進程間是可見的,因此,用它可以實現限制同時對一個資源的有限個訪問。
相關函數
1.CreateSemaphore()
CreateSemaphore(lpSemaphoreAttributes As SECURITY_ATTRIBUTES, ByVal lInitialCount As Long, ByVal lMaximumCount As Long, ByVal lpName As String);
該函數是
Windows提供用來創建一個Semaphore信號的函數,其參數含義如下:
lpSemaphoreAttributes:
安全屬性參數,是為Windows NT設置的,在Windows 95下可以忽略。但是在VB中若如上述聲明,則不能忽略,忽略后該函數有時不能正確執行,并返回0。此時,可以設置其為默認值,或者改為Byval lpSemaphoreAttributes as long,然后再傳入0。
lInitialCount:Semaphore的初始值,一般設為0或lMaxmumCount。
lMaximunCount:Semaphore信號的最大值。
lpName:該信號名,以便其他進程對其進行調用,若是相同進程可以設為Null。
函數成功時返回創建的Semaphore信號的句柄。該函數有一個特點,就是在要創建的信號已經創建了的情況下,它等同于函數OpenSemaphore(),僅僅是打開該Semaphore信號,并返回信號句柄。
2.ReleaseSemaphore()
ReleaseSemaphore(ByVal hSemaphore As Long, ByVal lReleaseCount As Long,lpPreviousCount As Long);
hSemaphore:函數CreateSemaphore()返回的Semaphore信號句柄;
lReleaseCount: 當前信號值的改變量;
lpPreviousCount:返回的Semaphore信號被加之前的值,可用于跟蹤
測試。
如果Semaphore信號當前值加上lReleaseCount后不超過CreateSemaphore()中設定的最大值lMaximunCount,函數返回1(True),否則返回0(False),可用GetLastError()得到其失敗的詳細原因。
3.WaitForSingleObject()
WaitForSingleObject(ByVal hHandle As Long,
ByVal dwMilliseconds As Long);
hHandle:等待對象的句柄;
dwMilliseconds:等待時間。
該函數可以實現對一個可等待對象的等待操作,獲取操作執行權。當等待的對象被釋放時函數成功返回,同時使等待對象變為有信號狀態,或者超時返回。該函數用于等待Semaphore信號時,若Semaphore信號不為0,則函數成功返回,同時使Semaphore信號記數減1。
我們可以利用它建立一個記數信號,每次當相同的程序加載時使記數器減1,退出的時候使計數器加1,這樣就可以限制相同程序的多份拷貝同時運行。
編程實現
下面的這段代碼用于限制一個程序最多只能同時運行4個實例:
Private Declare Function ReleaseSemaphore Lib “kernel32”(ByVal hSemaphore As Long, ByVal lReleaseCount As Long, lpPreviousCount As Long) As Long
Private Declare Function CreateSemaphore Lib “kernel32” Alias “CreateSemaphoreA”
(lpSemaphoreAttributes As SECURITY_ATTRIBUTES, ByVal lInitialCount As Long, ByVal lMaximumCount As Long, ByVal lpName As String) As Long
Private Declare Function WaitForSingleObject Lib “kernel32” (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type
Dim Semaphore As String, Sema As long, Security As SECURITY_ATTRIBUTES
Dim PrevSemaphore As Long, Turn As Long
Private Sub Form_Load()
Security.bInheritHandle = True
'默認的安全值
Security.lpSecurityDescriptor = 0
Security.nLength = Len(Security)
Semaphore = “Instance”
’創建或打開一個Semaphore記數信號,設資源空閑使用量為4
Sema = CreateSemaphore(Security, 4, 4, Semaphore)
'申請一個權限,并立即返回
Turn = WaitForSingleObject (Sema, 0)
'如果不是正常返回,則表示沒有申請到資源的使用權限
If Turn <> 0 Then
MsgBox “Full!”
End
End If
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
’在當前值上加1,表示有一個程序退出,釋放了一個權限,PrevSemaphore參數接收釋放前的計數器的值
ReleaseSemaphore Sema, 1, PrevSemaphore
End Sub
小 結
編譯后生成可執行文件Semaphore.exe。運行第一個實例后,申請的等待立刻正常返回,此時計數器的值為3,運行第4個實例后計數器的值為0,當試圖運行第5個實例時,由于此時已無可用的計數器資源,所以立刻返回一個失敗的等待,通知程序不能再運行更多的實例,并立刻退出。這種信號機制是進程間通信的一種重要機制,課本中常常用超市收款機的排隊機制來做比喻,其實現原理就是把WaitForSingleObject的等待時間設置為無窮大,直到有一個實例(顧客)退出(服務完),后面等待的實例就可以運行了。但是在實際編程中,一個無限等待(被凍結)的進程沒有什么實際用處,沒有必要繼續等待,所以等待時間通常都設為0,如果等不到資源就立刻退出。
本程序在VB 6.0企業版、Windows 98下調試通過。
原文轉自:http://www.anti-gravitydesign.com