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