免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
《windows核心編程系列 》六談?wù)劸€程調(diào)度、優(yōu)先級和關(guān)聯(lián)性

http://blog.csdn.net/ithzhang/article/details/8046723轉(zhuǎn)載請注明出處!

線程調(diào)度、優(yōu)先級和關(guān)聯(lián)性 

    每個(gè)線程都有一個(gè)CONTEXT結(jié)構(gòu),保存在線程內(nèi)核對象中。大約每隔20ms windows就會(huì)查看所有當(dāng)前存在的線程內(nèi)核對象。并在可調(diào)度的線程內(nèi)核對象中選擇一個(gè),將其保存在CONTEXT結(jié)構(gòu)的值載入cpu寄存器。這被稱為上下文切換。大約又過20ms  windows將當(dāng)前cpu寄存器存回內(nèi)核對象,線程被掛起。Windows再次檢查內(nèi)核對象,并在可調(diào)度的內(nèi)核對象中選擇一個(gè)進(jìn)行調(diào)度。此過程不斷重復(fù)直到系統(tǒng)關(guān)閉。

 

    Windows被稱為搶占式多線程系統(tǒng),系統(tǒng)可以在任何時(shí)刻停止一個(gè)線程而另行調(diào)度另外一個(gè)線程。我們對此可以有一些控制,但是權(quán)限很小。我們無法保證線程總在運(yùn)行或者獲得整個(gè)處理器。

 

     由于windows并不是實(shí)時(shí)操作系統(tǒng),我們無法保證在某一時(shí)間段一定在運(yùn)行。

 

     一般情況下,系統(tǒng)中的可調(diào)度線程很少。因?yàn)樗鼈兌荚诘却硞€(gè)事件的到來。比如notepad程序在等待用戶輸入的時(shí)候它就是不可調(diào)度的。它在等待鍵盤的輸入消息。當(dāng)我們向notepad中輸入時(shí)也并不意味著notepad會(huì)立即獲得cpu時(shí)間。原因就是:windows并不是實(shí)時(shí)調(diào)度系統(tǒng)。

 

    線程內(nèi)核對象中有一個(gè)值表示掛起計(jì)數(shù)。調(diào)用CreateThread時(shí)系統(tǒng)創(chuàng)建線程內(nèi)核對象,并把掛起計(jì)數(shù)初始化為1。這樣cpu就不會(huì)調(diào)度它。在初始化之后,系統(tǒng)檢查是否有CREATE_SUSPEND標(biāo)識(shí)傳入。如果有函數(shù)返回,進(jìn)程仍保持掛起狀態(tài)。否則將掛起計(jì)數(shù)遞減為0,此時(shí)線程就可以被調(diào)度了。

 

    通過創(chuàng)建一個(gè)掛起的進(jìn)程或線程我們可以在它們執(zhí)行任何代碼前改變它們的環(huán)境,比如將其添加到作業(yè)中或是改變優(yōu)先級。然后將它們設(shè)為可調(diào)度的。這可以通過調(diào)用ResumeThread函數(shù)。ResumeThread執(zhí)行成功將返回前一次的掛起計(jì)數(shù)。失敗則返回0xFFFFFFFF。

 

    一個(gè)線程可以被掛起多次。除了在創(chuàng)建時(shí)傳入CREATE_SUSPEND標(biāo)識(shí)外,還可以調(diào)用SuspendThread函數(shù)。第一個(gè)參數(shù)為想要掛起的線程句柄。任何線程都可以掛起另一個(gè)線程。掛起n次的線程要想變?yōu)榭烧{(diào)度的必須調(diào)用ResumeThread()n次。

 

實(shí)際開發(fā)中,在調(diào)用SuspendThread時(shí)必須非常小心,因?yàn)槲覀儫o法知道線程此時(shí)在干什么。如果一個(gè)線程在分配堆中的內(nèi)存,線程將鎖定堆,其他想要分配堆的線程將被掛起。直到第一個(gè)線程分配完畢。如果第一個(gè)線程被掛起,將會(huì)出現(xiàn)死鎖的情況。

 

    由于進(jìn)程不是cpu調(diào)度的單位,所以不存在掛起進(jìn)程的概念。但是我們可以掛起進(jìn)程中所有的線程。可以調(diào)用調(diào)試器函數(shù)WaitForDebugEvent函數(shù)?;謴?fù)時(shí)可以調(diào)用ContinueDebugEvent。

 

    除了被別人調(diào)用SuspendThread掛起外,線程也可以告訴系統(tǒng)在一段時(shí)間內(nèi),可以將自己掛起,不需要調(diào)度。這可以調(diào)用Sleep實(shí)現(xiàn)。

    

  1. void Sleep(DWORD dwMilliseconds);  


 

    參數(shù)表示線程自己掛起的時(shí)間。但是實(shí)際的掛起時(shí)間只是近似于所設(shè)定的參數(shù)。Windows并不是實(shí)時(shí)操作系統(tǒng),不能保證線程可以準(zhǔn)時(shí)醒來。實(shí)際時(shí)間取決于系統(tǒng)中其他線程的運(yùn)行情況。當(dāng)為其傳入0時(shí),表示主調(diào)線程主動(dòng)放棄本次時(shí)間片的剩余部分。注意是本次。

 

    系統(tǒng)提供一個(gè)名為SwitchToThread函數(shù),如果存在另一個(gè)可調(diào)度的線程,那么系統(tǒng)將讓此線程運(yùn)行。

    BOOL SwitchToThread();

    調(diào)用此函數(shù)時(shí),系統(tǒng)查看是否存在急需cpu時(shí)間的饑餓線程。如沒有則函數(shù)返回。如果存在,SwitchToThread將調(diào)度該線程。它與Sleep(0)很相似。區(qū)別在于SwitchToThread允許執(zhí)行低優(yōu)先級線程。

 

    當(dāng)我們需要計(jì)算線程執(zhí)行某項(xiàng)任務(wù)的我的時(shí)間時(shí),很多人習(xí)慣使用GetTickCount64函數(shù)。

 

  1. ULONG start=GetTickCount64();  
  2.   
  3.   //do something.  
  4.   
  5. ULONG end=GetTickCount64();  
  6.   
  7.        


 

 此段代碼有個(gè)前提就是代碼執(zhí)行不會(huì)被中斷。但是在搶占式OS中,線程可以隨時(shí)被終止。執(zhí)行上述代碼的線程可能在執(zhí)行第一個(gè)函數(shù)后就被掛起。一段時(shí)間后再次被調(diào)度。這時(shí)候時(shí)間就不準(zhǔn)確了。

 

    Windows提供了一個(gè)函數(shù)可以返回一個(gè)線程以獲得cpu時(shí)間:   

   

  1. BOOL GetThreadTime(  
  2.   
  3.         HANDLE hThread,  
  4.   
  5.         PFILETIME pftCreationTime,  
  6.   
  7.         PFILETIME pftExitTime,  
  8.   
  9.        PFILETIME pftKernelTime,  
  10.   
  11.        PFILETIME pftUserTime);  
  12.   
  13.       


 

   第一個(gè)參數(shù)為想獲得的線程句柄。

    第二個(gè)參數(shù)返回(線程創(chuàng)建時(shí)間-1601110:00)的秒數(shù)。單位是100ns。

    第三個(gè)表示退出時(shí)間-1601110:00的秒數(shù)。單位是100ns。

    第四個(gè)表示線程執(zhí)行內(nèi)核模式下的時(shí)間的絕對值。單位是100ns。

    第五個(gè)表示線程執(zhí)行用戶模式代碼的時(shí)間的絕對值。單位是100ns。

    類似的,GetProcessTime可以返回進(jìn)程中所有線程的時(shí)間之和。

    在進(jìn)行高精度的計(jì)算時(shí)上述函數(shù)仍然不夠。此時(shí)windows提供了以下函數(shù):

   

  1. BOOL QueryPerformanceFrequency(LARGE_INTEGER *pliFrequency)  
  2.   
  3. BOOL  QueryPerformanceCounter(LARGE_INTEGER *pliCount);  
  4.   
  5.       


 

    這兩個(gè)函數(shù)假設(shè)正在執(zhí)行的線程不會(huì)被搶占。它們都是針對生命期很短的代碼塊。GetCPUFrequencyInMHZ可以獲得cpu頻率。

    在windows定義的所有數(shù)據(jù)結(jié)構(gòu)中,CONTEXT結(jié)構(gòu)是唯一一個(gè)依賴于cpu的。我們可以通過調(diào)用GetThreadContext來獲得當(dāng)期cpu寄存器的狀態(tài)。

   

  1. BOOL GetThreadContext(  
  2.   
  3.        HANDLE pThread,  
  4.   
  5.        PCONTEXT pContext);  


 

   第二個(gè)參數(shù)是CONTEXT結(jié)構(gòu)指針。在分配CONTEXT結(jié)構(gòu)后,需要初始化ContextFlag標(biāo)志,表示以表示要獲取哪些寄存器。函數(shù)執(zhí)行后CONTEXT對象中就填入我們請求的成員。ContextFlag可以是:

CONTEXT_CONTROL表示控制寄存器。

    CONTEXT_INTEGER表示整數(shù)寄存器。

    CONTEXT_FLOAT 表示浮點(diǎn)寄存器。

    CONTEXT_ALL 表示CONTEXT_CONTROL |CONTEXT_INTEGER|CONTEXT_SEGMENTS。

    在調(diào)用GetThreadContext時(shí),需要先調(diào)用SuspendThread。因?yàn)樵谡{(diào)用GetThreadContext時(shí)系統(tǒng)可能正在執(zhí)行那個(gè)線程,此時(shí)線程的上下文與獲得的信息就不一致了。注意,它只能返回線程的用戶模式上下文。如果當(dāng)調(diào)用SuspendThread時(shí)線程正在內(nèi)核模式運(yùn)行,線程不會(huì)暫停,直到其返回用戶空間。但是返回到用戶控件后不會(huì)執(zhí)行任何用戶模式代碼。

    不僅僅能獲得線程的進(jìn)程上下文,我們還可以設(shè)置它。這可以調(diào)用:

   

  1. BOOL SetThreadContext()  
  2.   
  3.        HANDLE hThread,  
  4.   
  5.        CONST CONTEXT *pContext);  


 

    GetThreadContext和SetThreadContext函數(shù)為我們提供了對線程許多控制的方法,但是需要小心使用。

    線程優(yōu)先級

    前面提到的調(diào)度程序在調(diào)度另外一個(gè)線程之前,可以運(yùn)行一個(gè)線程大約20ms的時(shí)間。但是這是所有優(yōu)先級都相同的情況。實(shí)際上系統(tǒng)中的很多線程優(yōu)先級是不同的,這將影響調(diào)度程序如何選擇下一個(gè)要運(yùn)行的線程。

    Windows的線程優(yōu)先級從031。每個(gè)線程都會(huì)分配一個(gè)優(yōu)先級。當(dāng)系統(tǒng)確定給哪個(gè)線程分配cpu時(shí),它會(huì)首先查看優(yōu)先級為31的線程,直至所有優(yōu)先級為31的線程都被調(diào)度。然后再查看下一優(yōu)先級線程。只要存在優(yōu)先級為31的線程,系統(tǒng)就不會(huì)調(diào)度0-30級的線程。低優(yōu)先級線程長時(shí)間得不到cpu時(shí)間,這被稱為饑餓。這不經(jīng)常出現(xiàn),因?yàn)榇蠖鄶?shù)線程都是不可調(diào)度的。

    系統(tǒng)啟動(dòng)時(shí)會(huì)創(chuàng)建一個(gè)優(yōu)先級為0idle線程,整個(gè)系統(tǒng)只有它的優(yōu)先級為0。它在系統(tǒng)中沒有其他線程運(yùn)行時(shí)將系統(tǒng)內(nèi)存中所有閑置頁面清0。

    Windows中的線程優(yōu)先級是由優(yōu)先級類和相對線程優(yōu)先級來確定的。系統(tǒng)通過線程的相對優(yōu)先級加上線程所屬進(jìn)程的優(yōu)先級來確定線程的優(yōu)先級值。這個(gè)值被稱為線程的基本優(yōu)先級值。

    Windows支持6個(gè)進(jìn)程優(yōu)先級類:idle ,below normal ,normal ,above normal,highreal-time。它們是相對與進(jìn)程的。Normal最為常用,為99%的進(jìn)程使用。

    idle優(yōu)先級類在系統(tǒng)什么都不做的時(shí)候運(yùn)行的應(yīng)用程序。如屏幕保護(hù)程序。real-time優(yōu)先級類優(yōu)先級別最高,但是沒有開放給用戶使用。因?yàn)榇藘?yōu)先級類的程序會(huì)影響操作系統(tǒng)的任務(wù)。

    Windows支持7個(gè)相對線程優(yōu)先級:idle,lowest below normal,normal,above normal,highesttime-critical。這些優(yōu)先級是相對于進(jìn)程優(yōu)先級的。大多數(shù)的線程使用normal優(yōu)先級。

    概括起來就是進(jìn)程屬于某個(gè)優(yōu)先級類,另外還可以指定進(jìn)程中線程的相對線程優(yōu)先級。也就是說線程優(yōu)先級是相對于進(jìn)程優(yōu)先級的。time-critical優(yōu)先級對于real-time優(yōu)先級類,優(yōu)先級為31。相對于其他優(yōu)先級類則為15。

    需要注意的是進(jìn)程優(yōu)先級是抽象的概念,因?yàn)檫M(jìn)程并不參與調(diào)度。

在優(yōu)先級編程時(shí),首先需要在調(diào)用CreateProcess時(shí)可以再fdwCreate參數(shù)中傳入想要的優(yōu)先級。fdwCreate可以是以下標(biāo)識(shí)符:

real-time        REALTIME_PRIORITY_CLASS

high            HIGH_PRIORITY_CLASS

above normal     ABOVE_NORMAL_PRIORITY_CLASS

normal          NORMAL_PRIORITY_CLASS

below_normal    BELOW_NORMAL_PRIORITY_CLASS

idle             IDLE_PRIORITY_CLASS

進(jìn)程運(yùn)行后可以調(diào)用SetPrioritClass來改變進(jìn)程優(yōu)先級類。

    

  1. BOOL SetPriorityClass(  
  2.   
  3.          HANDLE hProcess,  
  4.   
  5.          DWORD fdwPriority);  
  6.   
  7.       


 

   可以調(diào)用GetPriorityClass來獲得進(jìn)程的優(yōu)先級類。

    DWORD GetPriorityClass(HANDLE hProcess);

    上面是指定的進(jìn)程優(yōu)先級類,調(diào)用CreateThread創(chuàng)建線程時(shí),它的線程優(yōu)先級總是被設(shè)置為normal??梢哉{(diào)用以下函數(shù)來改變線程優(yōu)先級:

    

  1. BOOL SetThreadPriority(  
  2.   
  3.         HANDLE hThread,  
  4.   
  5.     int nPriority);  


 

  nPriority可以是以下標(biāo)識(shí)符:

time-critical       THREAD_PRIORITY_TIME_CRITICAL

highest           THREAD_PRIORITY_HIGHEST

above-normal      THREAD_PRIORITY_ABOVE_NORMAL

normal           THREAD_PRIORITY_NORMAL

below-normal      THREAD_PRIORITY_BELOW_NORMAL

lowest            THREAD_PRIORITY_LOWEST

idle              THREAD_PRIORITY_IDLE

   但是在調(diào)用CreateThread時(shí)需要傳入CREATE_SUSPEND,使線程暫停執(zhí)行。

    相應(yīng)的可以調(diào)用int GetThreadPriority(HANDLE hThread);返回線程相對優(yōu)先級。

     Windows并沒有返回線程優(yōu)先級的函數(shù),而是分別提供返回進(jìn)程優(yōu)先級類和相對線程優(yōu)先級。

    有些時(shí)候,系統(tǒng)也會(huì)提升一個(gè)線程的優(yōu)先級。比如某個(gè)線程正在等待用戶按鍵消息。當(dāng)用戶敲了一個(gè)鍵,系統(tǒng)會(huì)在線程的消息隊(duì)列中放入一個(gè)WM_KEYDOWN消息。此時(shí)線程就變成可調(diào)度的了。鍵盤設(shè)備驅(qū)動(dòng)程序?qū)⑹瓜到y(tǒng)臨時(shí)提升線程的優(yōu)先級。在該時(shí)間片結(jié)束后,系統(tǒng)會(huì)將線程的優(yōu)先級值減一,第三個(gè)時(shí)間片執(zhí)行時(shí)再減去一。直至保持基本優(yōu)先級運(yùn)行。

    注意:線程的當(dāng)前優(yōu)先級不會(huì)低于進(jìn)程的基本優(yōu)先級。而且設(shè)備驅(qū)動(dòng)程序可以決定動(dòng)態(tài)提升的幅度。系統(tǒng)只提升優(yōu)先級值在1~15的線程。這個(gè)范圍被稱為動(dòng)態(tài)優(yōu)先級范圍??梢酝ㄟ^調(diào)用以下函數(shù)來禁止系統(tǒng)對線程優(yōu)先級進(jìn)行動(dòng)態(tài) 提升:

    

  1. BOOL SetProcessPriorityBoost(  
  2.   
  3.        HANDLE hProcess,  
  4.   
  5.        BOOL bDisablePriorityBoost);  


 

    此函數(shù)禁止動(dòng)態(tài)提升此進(jìn)程內(nèi)的所有線程的優(yōu)先級。

    

  1. BOOL SetThreadPriorityBoost(  
  2.   
  3.        HANDLE hThread,  
  4.   
  5.        BOOL bDisablePriorityBoost);  


 

    此函數(shù)禁止動(dòng)態(tài)提升某個(gè)線程的優(yōu)先級。

還有一種動(dòng)態(tài)提升優(yōu)先級的情況:檢測到有饑餓情況出現(xiàn)時(shí),也就是某個(gè)線程由于優(yōu)先級低,而長時(shí)間無法得到調(diào)度時(shí)。系統(tǒng)就會(huì)動(dòng)態(tài)提升此線程的優(yōu)先級。系統(tǒng)允許它運(yùn)行兩個(gè)時(shí)間片。兩個(gè)時(shí)間片結(jié)束之后立即恢復(fù)到基本優(yōu)先級。

用戶正在使用的窗口被稱為前臺(tái)窗口。這個(gè)進(jìn)程就被稱為前臺(tái)進(jìn)程。為了改進(jìn)前臺(tái)進(jìn)程的響應(yīng)性,windows會(huì)為前臺(tái)進(jìn)程中的線程微調(diào)調(diào)度算法。是前臺(tái)進(jìn)程的線程分配比一般情況下更多的時(shí)間片。

    關(guān)聯(lián)性

    默認(rèn)情況下,windows在分配cpu時(shí)采用軟關(guān)聯(lián)的方式。也就是說在其他因素相同的情況下,系統(tǒng)使線程在上一次運(yùn)行的處理器上運(yùn)行。這有助于重用仍在處理器高速緩存中的數(shù)據(jù)。

系統(tǒng)在啟動(dòng)時(shí)確定cpu數(shù)量。應(yīng)用程序可以通過調(diào)用GetSysInfo來查詢cpu的數(shù)量。如果需要限制一個(gè)進(jìn)程的所有線程在某些cpu上運(yùn)行,可以調(diào)用:

  1. BOOL SetProcessAffinityMask(  
  2.   
  3.          HANDLE hProcess,  
  4.   
  5.          DWORD_PTR dwProcessAffinityMask);  


 

第一個(gè)參數(shù)代表要設(shè)置的進(jìn)程句柄。

第二參數(shù)是一個(gè)位掩碼。代表線程可以在哪些cpu上運(yùn)行。

注意子進(jìn)程將繼承父進(jìn)程的關(guān)聯(lián)性。

    GetProcessAffinityMask返回進(jìn)程的關(guān)聯(lián)掩碼。

    相應(yīng)的還可以設(shè)置某個(gè)線程只在一組cpu上運(yùn)行:

    SetThreadAffinityMask。

    有時(shí)候強(qiáng)制一個(gè)線程只在某個(gè)特定的cpu上運(yùn)行并不是什么好主意。Windows允許一個(gè)線程運(yùn)行在一個(gè)cpu上,但如果需要,它將被移動(dòng)到一個(gè)空閑的cpu上。

    要給線程設(shè)置一個(gè)理想的cpu,可以調(diào)用:

    

  1. DWORD SetThreadIdealProcessro(  
  2.   
  3.       HANDLE hThread  
  4.   
  5.       DWORD dwIdealProcessor);  


 

    dwIdealProcessor是一個(gè)031/63之間的整數(shù)。表示線程希望設(shè)置的cpu??梢詡魅?span style="font-family:Times New Roman">MAXIMUM_PROCESSOR值,表示沒有理想的cpu。

                                                  2012、9、28于山西大同

  

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
[CLR via C#]25. 線程基礎(chǔ)
《Windows via C/C 》學(xué)習(xí)筆記 —— 線程優(yōu)先級
Windows核心編程(第五版)筆記 第七章 線程調(diào)度、優(yōu)先級 (Thread Sched...
(轉(zhuǎn))Windows的線程管理和調(diào)度機(jī)制
淺議Visual C++多線程設(shè)計(jì)
我認(rèn)識(shí)的線程
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服