關於 TRTLCriticalSection
臨界區是一種最直接的執行緒同步方式。所謂臨界區,就是一次只能由一個執行緒來執行的一段程式碼。如果把初始化陣列的程式碼放在臨界區內,另一個執行緒在第一個執行緒處理完之前是不會被執行的。在使用臨界區之前,必須使用InitializeCriticalSection()過程來初始化它。 其宣告如下: procedure InitializeCriticalSection(var lpCriticalSection: TRTLCriticalSection); stdcall; lpCriticalSection引數是一個TRTLCriticalSection型別的記錄,並且是變參。至於TRTLCriticalSection是如何定義的,這並不重要,因為很少需要檢視這個記錄中的具體內容。只需要在lpCriticalSection中傳遞未初始化的記錄,InitializeCriticalSection()過程就會填充這個記錄。 注意Microsoft故意隱瞞了TRTLCriticalSection的細節。因為,其內容在不同的硬體平臺上是不同的。在基於Intel的平臺上,TRTLCriticalSection包含一個計數器、一個指示當前執行緒控制程式碼的域和一個系統事件的控制程式碼。在Alpha平臺上,計數器被替換為一種Alpha-CPU 資料結構,稱為spinlock。 在記錄被填充後,我們就可以開始建立臨界區了。這時我們需要用EnterCriticalSection()和LeaveCriticalSection()來封裝程式碼塊。這兩個過程的宣告如下: procedure EnterCriticalSection(var lpCriticalSection: TRTLCriticalSection); stdcall; procedure LeaveCriticalSection(var lpCriticalSection:TRTLCriticalSection); stdcall; 正如你所想的,引數lpCriticalSection就是由InitializeCriticalSection()填充的記錄。 當你不需要TRTLCriticalSection記錄時,應當呼叫DeleteCriticalSection()過程,下面是它的宣告: procedure DeleteCriticalSection(var lpCriticalSection:TRTLCriticalSection);stdcall 看看u2m(UpToMe)的例子: 在第一個執行緒呼叫了EnterCriticalSection()之後,所有別的執行緒就不能再進入程式碼塊。下一個執行緒要等第一個執行緒呼叫LeaveCriticalSection()後才能被喚醒。 當有多個執行緒的時候,經常需要去同步這些執行緒以訪問同一個資料或資源。例如,假設有一個程 序,其中一個執行緒用於把檔案讀到記憶體,而另一個執行緒用於統計檔案中的字元數。當然,在把整個文 件調入記憶體之前,統計它的計數是沒有意義的。但是,由於每個操作都有自己的執行緒,作業系統會把 兩個執行緒當作是互不相干的任務分別執行,這樣就可能在沒有把整個檔案裝入記憶體時統計字數。為解 決此問題,你必須使兩個執行緒同步工作。 存在一些執行緒同步地址的問題,Win32提供了許多執行緒同步的方式。在本節你將看到使用臨界區、 互斥、訊號量和事件來解決執行緒同步的問題。 1. 臨界區 臨界區是一種最直接的執行緒同步方式。所謂臨界區,就是一次只能由 一個執行緒來執行的一段程式碼。如果把初始化陣列的程式碼放在臨界區內,另 一個執行緒在第一個執行緒處理完之前是不會被執行的。 在使用臨界區之前,必須使用InitializeCriticalSection()過程來初始化它。 其宣告如下: procedure InitializeCriticalSection(var lpCriticalSection: TRLCriticalSection);stdcall; lpCriticalSection引數是一個TRTLCriticalSection型別的記錄,並且是變參。至於TRTLCriticalSection 是如何定義的,這並不重要,因為很少需要檢視這個記錄中的具體內容。只需要在lpCriticalSection中傳 遞未初始化的記錄,InitializeCriticalSection()過程就會填充這個記錄。 注意Microsoft故意隱瞞了TRTLCriticalSection的細節。因為,其內容在不同的硬體平臺上是 不同的。在基於Intel的平臺上,TRTLCriticalSection包含一個計數器、一個指示當前執行緒控制程式碼 的域和一個系統事件的控制程式碼。在Alpha平臺上,計數器被替換為一種Alpha-CPU 資料結構,稱 為spinlock。在記錄被填充後,我們就可以開始建立臨界區了。這時我們需要用EnterCriticalSection()和 LeaveCriticalSection()來封裝程式碼塊。這兩個過程的宣告如下: procedure EnterCriticalSection(var lpCriticalSection:TRRLCriticalSection);stdcall; procedure LeaveCriticalSection(var lpCriticalSection:TRRLCriticalSection);stdcall; 正如你所想的,引數lpCriticalSection就是由InitializeCriticalSection()填充的記錄。 當你不需要TRTLCriticalSection記錄時,應當呼叫DeleteCriticalSection()過程,下面是它的宣告: procedure DeleteCriticalSection(var lpCriticalSection: TRTLCriticalSection); stdcall; 2. 互斥 互斥非常類似於臨界區,除了兩個關鍵的區別:首先,互斥可用於跨 程式的執行緒同步。其次,互斥能被賦予一個字串名字,並且通過引用此 名字建立現有互斥物件的附加控制程式碼。 提示臨界區與事件物件(比如互斥物件)的最大的區別是在效能上。臨 界區在沒有執行緒衝突時,要用1 0 ~ 1 5個時間片,而事件物件由於涉及到 系統核心要用400~600個時間片。 可以呼叫函式CreateMutex ( )來建立一個互斥量。下面是函式的宣告: function CreateMutext(lpMutextAtrribes:PSecurityAttributtes; bInitalOwner:BOOL; lpName:PChar):THandle; stdcall; lpMutexAttributes引數為一個指向TSecurityAttributtes記錄的指標。此引數通常設為0,表示預設的 安全屬性。bInitalOwner參數列示建立互斥物件的執行緒是否要成為此互斥物件的擁有者。當此引數為False時, 表示互斥物件沒有擁有者。 lpName引數指定互斥物件的名稱。設為nil表示無命名,如果引數不是設為nil,函式會搜尋是否有 同名的互斥物件存在。如果有,函式就會返回同名互斥物件的控制程式碼。否則,就新建立一個互斥物件並 返回其控制程式碼。 當使用完互斥物件時,應當呼叫CloseHandle()來關閉它。 在程式中使用WaitForSingleObject()來防止其他執行緒進入同步區域的程式碼。此函式聲 明如下: function WaitForSingleObject(hHandle: THandle; dwMilliseconds: DWORD): DWORD; stdcall; 這個函式可以使當前執行緒在dwMilliseconds指定的時間內睡眠,直到hHandle引數指定的物件進入 發訊號狀態為止。一個互斥物件不再被執行緒擁有時,它就進入發訊號狀態。當一個程式要終止時,它 就進入發訊號狀態。dwMilliseconds引數可以設為0,這意味著只檢查hHandle引數指定的物件是否處於 發訊號狀態,而後立即返回。dwMilliseconds引數設為INFINITE,表示如果訊號不出現將一直等下去。 這個函式的返回值如下 WaitFor SingleObject()函式使用的返回值 返回值 含義 WAIT_ABANDONED 指定的物件是互斥物件,並且擁有這個互斥物件的執行緒在沒有釋放此物件之 前就已終止。此時就稱互斥物件被拋棄。這種情況下,這個互斥物件歸當前線 程所有,並把它設為非發訊號狀態 WAIT_OBJECT_0 指定的物件處於發訊號狀態 WAIT_TIMEOUT等待的時間已過,物件仍然是非發訊號狀態 再次宣告,當一個互斥物件不再被一個執行緒所擁有,它就處於發訊號狀態。此時首先呼叫WaitForSingleObject()函式 的執行緒就成為該互斥物件的擁有者,此互斥物件設為不發訊號狀態。當執行緒呼叫 ReleaseMutex()函式並傳遞一個互斥物件的控制程式碼作為引數時,這種擁有關係就被解除,互斥物件重新 進入發訊號狀態。 注意除WaitForSingleObject()函式外,你還可以使用WaitForMultipleObject()和MsgWaitForMultipleObject()函式, 它們可以等待幾個物件變為發訊號狀態。這兩個函式的詳細情況請看 Win32 API聯機文件。 3. 訊號量 另一種使執行緒同步的技術是使用訊號量物件。它是在互斥的基礎上建立的,但訊號量增加了資源 計數的功能,預定數目的執行緒允許同時進入要同步的程式碼。可以用CreateSemaphore()來建立一個訊號 量物件,其宣告如下: function CreateSemaphore(lpSemaphoreAttributes: PSecurityAttributes; lInitialCount, lMaximumCount: Longint; lpName: PChar): THandle; stdcall; 和CreateMutex()函式一樣,CreateSemaphore()的第一個引數也是一個指向TSecurityAttribute s記錄 的指標,此引數的預設值可以設為nil。 lInitialCount引數用來指定一個訊號量的初始計數值,這個值必須在0和lMaximumCount之間。此 引數大於0,就表示訊號量處於發訊號狀態。當呼叫WaitForSingleObject()函式(或其他函式)時,此計 數值就減1。當呼叫ReleaseSemaphore()時,此計數值加1。 引數lMaximumCount指定計數值的最大值。如果這個訊號量代表某種資源,那麼這個值代表可用 資源總數。 引數lpName用於給出訊號量物件的名稱,它類似於CreateMutex()函式的lpName引數。 |
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7299296/viewspace-617782/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 關於IT,關於技術
- 關於
- 關於~
- 關於RedisRedis
- 關於REMREM
- 關於IntentIntent
- 關於HTMLHTML
- 關於 kafkaKafka
- 關於 UndefinedUndefined
- 關於ScrumScrum
- 關於startActivityForResult
- 關於synchronizedsynchronized
- 關於抽象抽象
- 關於GitGit
- 關於MySQLMySql
- 關於lispLisp
- 關於HAIPAI
- 關於 NSMapTableAPT
- 關於sessionSession
- 關於BuilderUI
- 關於打包
- 關於jbuilderUI
- 關於prototype
- 關於NULLNull
- 關於YUIUI
- 關於面試面試
- 關於NVMe
- 關於namespacenamespace
- 關於列印
- 關於液泡
- 關於AUC
- 關於RE
- 關於裁員
- 關於RESTREST
- 關於 webmWeb
- 關於我
- 關於mavenMaven
- 關於思路