若干種內核對象,包括進程,線程和作業。可以將所有這些內核對象用于同步目的。對于線程同步來說,這些內核對象中的每種對象都可以說是處于已通知或未通知的狀態之中。
例如::當進程正在運行的時候,進程內核對象處于未通知狀態,當進程終止運行的時候,它就變為已通知狀態。進程內核對象中是個布爾值,當對象創建時,該值被初始化為FALSE(未通知狀態)。當進程終止運行時,操作系統自動將對應的對象布爾值改為TRUE,表示該對象已經得到通知。當線程終止運行時,操作系統會自動將線程對象的狀態改為已通知狀態。因此,可以將相同的方法用于應用程序,以確定線程是否不再運行。
1、等待函數。
等待函數可使線程自愿進入等待狀態,直到一個特定的內核對象變為已通知狀態為止:WaitForSingleObject
2、成功等待的副作用。
當事件對象變為已通知狀態時,函數就會發現這個情況,并將WAITOBJECT0返回給調用線程。但是就在函數返回之前,該事件將被置為未通知狀態,這就是成功等待的副作用。(空談啊,空談啊...)
如果多個線程等待單個內核對象,那么當該對象變成已通知狀態時,系統究竟決定喚醒哪個線程呢?
等待了最長時間的線程將得到該對象。系統會讓線程暫停運行。如果一個線程等待一個對象,然后該線程暫停運行,那么系統就會忘記該線程正在等待該對象。這是一個特性,因為沒有理由為一個暫停運行的線程進行調度。當后來該線程恢復運行時,系統將認為該線程剛剛開始等待該對象。
3、事件內核對象
在所有的內核對象中,事件內核對象是個最基本的對象。它們包含一個使用計數(與所有內核對象一樣),一個用于指明該事件是個自動重置的事件還是一個人工重置的事件的布爾值,另一個用于指明該事件處于已通知狀態還是未通知狀態的布爾值。注意:
(1)、人工重置事件與自動重置事件的區別。
事件能夠通知一個操作已經完成。有兩種不同類型的事件對象。一種是人工重置的事件,另一種是自動重置的事件。
當人工重置的事件得到通知時,等待該事件的
所有線程均變為可調度線程。
當一個自動重置的事件得到通知時,等待該事件的線程中
只有一個線程變為可調度線程。
當線程成功地等待到該對象時,自動重置的事件就會自動重置到未通知狀態。這就是自動重置的事件如何獲得它們的名字的方法。通常沒有必要為自動重置的事件調用ResetEvent函數,因為系統會自動對事件進行重置。
(2)、使用createvent創建。注意參數:創建的是人工還是自動,匿名還是命名事件。對于命名事件只能創建一個。
(3)、PulseEvent函數使得事件變為已通知狀態,然后立即又變為未通知狀態。
4、等待定時器內核對象
等待定時器是在
某個時間或按規定的間隔時間發出自己的信號通知的內核對象。它們通常用來在某個時間執行某個操作。
若要創建等待定時器,只需要調用CreateWaitableTimer函數:
注意:
(1)、進程可以獲得它自己的與進程相關的現有等待定時器的句柄,方法是調用OpenWaitableTimer函數:
(2)、與事件的情況一樣有人工重置的定時器或自動重置的定時器。當發出人工重置的定時器信號通知時,等待該定時器的
所有線程均變為可調度線程。當發出自動重置的定時器信號通知時,只有
一個等待的線程變為可調度線程。
(3)、等待定時器對象總是在未通知狀態中創建。必須調用SetWaitableTimer函數來告訴定時器你想在何時讓它成為已通知狀態:每次調用SetWaitableTimer函數,都會在設置新的報時條件之前撤消定時器原來的報時條件
(4)、CancelWaitableTimer函數:這個簡單的函數用于取出定時器的句柄并將它撤消,這樣,除非接著調用SetWaitableTimer函數以便重新設置定時器,否則定時器決不會進行報時。
(5)、與用戶定時器(用SetTimer函數進行設置)進行比較:
①、它們之間的最大差別是,用
戶定時器需要在應用程序中設置許多附加的用戶界面結構,這使定時器變得資源更加密集。
②、等待定時器屬于內核對象,這意味著它們可以供多個線程共享,并且是安全的。用戶定時器能夠生成
WM_TIMER消息,這些消息將返回給調用SetTimer(用于回調定時器)的線程和創建窗口(用于基于窗口的定時器)的線程。因此,當用
戶定時器報時的時候,只有一個線程得到通知。另一方面,多個線程可以在等待定時器上進行等待,如果定時器是個人工重置的定時器,則可以
調度若干個線程。 ③、WM_TIMER消息始終屬于最低優先級的消息,當線程的隊列中沒有其他消息時,才檢索該消息。等待定時器的處理方法與其他內核對象沒有什么差別,如果定時器發出報時信息,而你的線程正在等待之中,那么你的線程就會醒來。
5、信標內核對象
信標內核對象
用于對資源進行計數。它們與所有內核對象一樣,包含
一個使用數量,但是它們也包含另外
兩個帶符號的3 2位值,一個是最大資源數量,一個是當前資源數量。最大資源數量用于標識信標能夠控制的資源的最大數量,而當前資源數量則用于標識當前可以使用的資源的數量。可以建立2 147 483 647個資源。
信標的使用規則如下:
• 如果當前資源的數量大于0,則發出信標信號。
• 如果當前資源數量是0,則不發出信標信號。
• 系統決不允許當前資源的數量為負值。
• 當前資源數量決不能大于最大資源
創建:通過createsemaphore創建
當向信標申請一個資源時,操作系統就要檢查是否有這個資源可供使用,同時將可用資源的數量遞減,而不讓另一個線程加以干擾。只有當資源數量遞減后,系統才允許另一個線程申請對資源的訪問權。
為了正確地說明這個問題,讓我們來看一看應用程序是如何使用信標的。
比如說,
我正在開發一個服務器進程,在這個進程中,我已經分配了一個能夠用來存放客戶機請求的緩沖區。我對緩沖區的大小進行了硬編碼,這樣它每次最多能夠存放5個客戶機請求。如果5個請求尚未處理完畢時,一個新客戶機試圖與服務器進行聯系,那么這個新客戶機的請求就會被拒絕,并出現一個錯誤,指明服務器現在很忙,客戶機應該過些時候重新進行聯系。當我的服務器進程初始化時,它創建一個線程池,里面包含5個線程,每個線程都準備在客戶機請求到來時對它進行處理。開始時,沒有客戶機提出任何請求,因此我的服務器不允許線程池中的任何線程成為可調度線程。但是,如果3個客戶機請求同時到來,那么線程池中應該有3個線程處于可調度狀態。使用信標,就能夠很好地處理對資源的監控和對線程的調度,最大資源數量設置為5,因為這是我進行硬編碼的緩沖區的大小。當前資源數量最初設置為0,因為沒有客戶機提出任何請求。當客戶機的請求被接受時,當前資源數量就遞增,當客戶機的請求被提交給服務器的線程池時,當前資源數量就遞減。
一些API函數對信標內核對象的操作
調用OpenSemaphore函數,另一個進程可以獲得它自己的進程與現有信標相關的句柄:
通過調用ReleaseSemaphore函數,線程就能夠對信標的當前資源數量進行遞增:
6、互斥內核對象
互斥對象(m u t e x)內核對象能夠確保線程擁有對單個資源的互斥訪問權。實際上互斥對象是因此而得名的。互斥對象包含一個使用數量,一個線程I D和一個遞歸計數器。
特點:
(1)、互斥對象的行為特性與關鍵代碼段相同,但是互斥對象屬于內核對象,而
關鍵代碼段則屬于用戶方式對象。這意味著互斥對象的運行速度比關鍵代碼段要慢。但是這也意味著
不同進程中的多個線程能夠訪問單個互斥對象,并且這意味著線程在等待訪問資源時
可以設定一個超時值。(2)、ID用于標識系統中的哪個線程當前擁有互斥對象,遞歸計數器用于指明該線程擁有互斥對象的次數。
(3)、它們用于保護由多個線程訪問的內存塊。如果多個線程要同時訪問內存塊,內存塊中的數據就可能遭到破壞。互
斥對象能夠保證訪問內存塊的任何線程擁有對該內存塊的獨占訪問權,這樣就能夠保證數據的完整性。
互斥對象的使用規則如下:
• 如果線程ID是0(這是個無效I D),互斥對象不被任何線程所擁有,并且發出該互斥對象的通知信號。
• 如果I D是個非0數字,那么一個線程就擁有互斥對象,并且不發出該互斥對象的通知信號。
• 與所有其他內核對象不同, 互斥對象在操作系統中擁有特殊的代碼,允許它們違反正常的規則
創建及一些常用API操作:
調用createmutex
另一個進程可以獲得它自己進程與現有互斥對象相關的句柄:openmutex
釋放:releasemutex,有多少次等待就有多少次釋放調用。
當遞歸計數器到達0時,該線程I D也被置為0,同時該對象變為已通知狀態。系統要查看是否有任何線程正在等待互斥對象。如果有,系統將“按公平原則”選定等待線程中的一個,為它賦予互斥對象的所有權。當然,這意味著線程I D被設置為選定的線程的I D,并且遞歸計數器被置為1。如果沒有其他線程正在等待互斥對象,那么該互斥對象將保持已通知狀態,這樣,等待互斥對象的下一個線程就立即可以得到互斥對象。
沒有一種對象能夠記住哪個線程成功地等待到該對象,只有互斥對象能夠對此保持跟蹤。
互斥對象的釋放:試圖釋放不是調用者擁有的互斥對象
當一個線程調用releasemutex函數時,該函數要查看調用線程的I D是否與互斥對象中的線程I D相匹配。如果兩個I D相匹配,遞歸計數器就會像前面介紹的那樣遞減。如果兩個線程的I D不匹配,那么releasemutex函數將不進行任何操作,而是將FALSE(表示失敗)返回給調用者。
如果在釋放互斥對象之前,擁有互斥對象的線程終止運行(使用E x i t T h r e a d、Te r m i n a t e T h r e a d、E x i t P r o c e s s或Te r m i n a t e P r o c e s s函數),那么互斥對象和正在等待互斥對象的其他線程將會發生什么情況呢?答案是,系統將把該互斥對象視為已經被放棄——擁有互斥對象的線程決不會釋放它,因為該線程已經終止運行。(故不宜使用這些函數)

//////////////////////待續
posted on 2011-10-08 00:10
Yu_ 閱讀(401)
評論(0) 編輯 收藏 引用 所屬分類:
Windows程序設計