1. 程式人生 > >linux核心--程序排程(一)

linux核心--程序排程(一)

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

                引言:無論是在批處理系統還是分時系統中,使用者程序數一般都多於處理機數、這將導致它們互相爭奪處理機。另外,系統程序也同樣需要使用處理機。這就要求程序排程程式按一定的策略,動態地把處理機分配給處於就緒佇列中的某一個程序,以使之執行。

 

程序排程的具體功能可總結為如下幾點:

   作為程序排程的準備,程序管理模組必須將系統中各程序的執行情況和狀態特徵記錄在各程序的PCB表中。並且,根據各程序的狀態特徵和資源需求等、程序管理模組還將各程序的PCB表排成相應的佇列並進行動態佇列轉接。程序排程模組通過PCB變化來掌握系統中存在的所有程序的執行情況和狀態特徵,並在適當的時機從就緒佇列中選擇出一個程序佔據處理機。

選擇佔有處理機的程序

  程序排程的主要功能是按照一定的策略選擇—個處於就緒狀態的程序,使其獲得處理機執行。根據不同的系統設計目的,有各種各樣的選擇策略,例如系統開銷較少的靜態優先數排程法,適合於分時系統的輪轉法(Round RoLin)和多級互饋輪轉法(Round Robin withMultip1e feedback)等。這些選擇策略決定了排程演算法的效能。

進行程序上下文切換

  —個程序的上下文(context)包括程序的狀態、有關變數和資料結構的值、機器暫存器的值和PCB以及有關程式、資料等。一個程序的執行是在程序的上下文中執行。當正在執行的程序由於某種原因要讓出處理機時,系統要做程序上下文切換,以使另一個程序得以執行。當進行上下文切換時點統要首先檢查是否允許做上下文切換(在有些情況下,上下文切換是不允許的,例如系統正在執行某個不允許中斷的原語時)。然後,系統要保留有關被切換程序的足夠資訊,以便以後切換回該程序時,順利恢復該程序的執行。在系統保留了CPU現場之後,排程程式選擇一個新的處於就緒狀態的程序、並裝配該程序的上下文,使CPU的控制權掌握在被選中程序手中。

 

Unix程序排程

   

   程序是程式的執行系統中活動的實體. 在UNIX系統中程序被定義為映像的執行. 映像是計算機的執行環境,它包括各種暫存器及儲存器的值、開啟檔案的狀態及現行目錄等等.程序映像的組成部分:暫存器、程序控制塊proc結構和user結構、程序資料區ppda (共享正文段(由text 結構控制) 、資料段和棧段( 含使用者棧和核心棧) ) . 對於一個程序的映像來說,proc 結構、程序頁表、text 結構是常駐記憶體的,而user 結構、正文段、資料段是非常駐記憶體部分. 它們在使用者虛擬空間形成一個整體,一起換進換出.

    在Unix作業系統中,所以的程式,不論是使用者級上還是在核心級上執行的,都出現在某個程序的現場內,所有的使用者程式都在它們自己的程序現場中執行。當這些使用者程序通過系統呼叫請求核心服務的時候,實現該系統呼叫的核心程式碼繼續在請求程序的現場內執行,這就能讓核心方便的訪問程序的所有狀態及其他地址空間。它還提供了一種代表使用者程式記錄核心執行的當前狀態的方式。例如,如果需要掛起一次系統呼叫的執行來等待I/O操作完成,那麼核心有關係統呼叫處理的狀態就要儲存在程序中。

    因為系統的所有活動,無論是使用者級上的還是核心級上的,都發生在某個程序的現場內,所有UNIX核心只調度需要執行的程序。當使用傳統的分時排程策略的時候,在使用者級執行的程序不會被分入時間內執行。只有當前的核心程序明確允許的情況下,才能切換到在核心執行的另一個程序。

   

UNIX程序排程核心思想


                          程序狀態轉換圖                              

  

程序排程機制問量

    在傳統Unix中.程序優先順序的設定是通過nice和set priority完成的;但不幸的是,速兩種系統呼叫無法使用最高優先順序的程序得以立即進行,這是因為在迴圈排程(時間片排程)機制下.當程序的時聞片用完後.不論擾先級如何都讓出CPU.另外,由於它是非搶佔式核心,優先順序高的程序不能 立即打斷當前正在執行的程序,獲得CPU資源.這對一些要求程序立即搶佔CPU,並且一次執行完成的實時應用是不能滿足要求的.

    UNIX系統是一個多使用者分時系統,其分時性是通過對使用者程序頻繁的排程來實現的,系統的排程程式分成兩部分,即處理機排程程式( swtch) 和程序對換程式(sched) . 在這裡我涉及的是處理機排程程式.在如下幾種情況下會呼叫處理機排程程式: (1) 若一個程序已到達它不能超過的某個點,這時它就要呼叫“sleep”,而“sleep”則呼叫“swtch”;(2) 一個在核心態下執行的程序,當它將要轉入使用者態之前,會測試變數“runrun”,如果其值非0 ,則意味著更高優先權的程序已為執行準備就緒. 此時核心態程序也將呼叫“swtch”.UNIX程序排程策略是基於動態優先數,優先數的設定有如下特點:

  swtch 由“trap”、“sleep”、“expand”、“exit”、“stop”、“xalloc”呼叫. 它是一個非常特殊的過程,分為三段執行,涉及3 個核心態程序.

①第一階段屬於當前程序的部分,若當前程序不是程序0 ,則呼叫savu過程將當前程序的環境變數儲存在u. u- rsav. 呼叫retu過程恢復程序0 的環境變數.

②第二階段屬於程序0 ,首先清runrun 標誌,該標誌指示一個較當前程序具有更高優先權的程序已為執行準備就緒.swtch通過do迴圈尋找最高優先權程序(重新計算各程序的優先順序) . 若找到了滿足條件的就緒程序,則將其從就緒佇列中取出,並將該程序的優先順序設定為當前的優先順序curpri.

③第三階段屬於被選中的程序. 該程序已成為當前程序開始執行,根據該程序的SSWAP 標誌是否設定,呼叫aretu過程從u. u-ssav 中恢復程序的環境變數(r5 和r6) .

 

    程式發現某程序優先順序高於當前執行程序的優先順序時,就要設定該標誌,而在中斷陷入處理程式結束之前,檢查該標誌是否設定,若已設定則呼叫swtch()程式進行排程,另外,在時鐘中斷處理中每隔1 秒也將runrun 標誌設定一次,並通過軟體中斷方式,執行swtch() 程式,這是為了增加排程機會,保證良好的分時性.Swtch 程式呼叫了savu、retu、idle、aretu 等過程。

savu 程式的作用:這是一個組合語言過程,它將r5 和r6 的值存放到一個數組中,該陣列的地址作為一個引數傳遞至savu ;

retu 程式的作用:組合語言過程,它復位第七個核心態段地址暫存器,然後從“u. u- rsa”最新可存取副本中復位r6 和r5 ;

aretu 程式的作用:組合語言過程,它從作為引數傳遞過來的地址重灌r5 和r6 ;

idle 程式的作用:組合語言過程,讓處理機空轉等待.

swtch 程式功能強大而其程式程式碼簡潔精練(共71行程式碼,其中註釋語句等有30 行,有效程式碼是41行) ,這也是整個UNIX系統程式碼的突出的特點.

 

Unix系統是多使用者,多工的作業系統,它通過向程序提供與機器無關的抽象服務,從而在Unix實現之間提供了高度的程式的可移植性。程式的執行被限制在保持程式當前狀態的程序內,這些狀態包括虛擬地址空間,程式的變數值以及硬體狀態。核心給每個程序提供了一個環境讓這個環境顯得好像該程序是系統中正在執行的唯一程序那樣。這主要是賦予每個程序自己的虛擬地址空間來實現的。系統呼叫可以建立新程序,改變程序正在執行的程式,以及終止程序,還可以使用其他許多系統呼叫,其中包括動態分配未初始化資料的系統呼叫。

   

 

 

Linux的程序排程

 

    傳統Unix作業系統的排程演算法必須實現幾個互相沖突的目標:程序響應時間儘可能快,後臺作業的吞吐量儘可能高,程序的飢餓現象儘可能避免,低優先順序和高優先順序程序的需要儘可能調和等等。決定什麼時候以怎樣的方式選擇一個新程序執行的這組規則就是所謂的排程策略(scheduling policy)。

    Linux的程序排程是基於分時技術(time-sharing)。允許多個程序“併發”執行就意味著CPU 的時間被粗略地分成“片”,給每個可執行程序分配一片。

    當然,單處理器在任何給定的時刻只能執行一個程序。當一個併發執行的程序其時間片或時限(quantum)到期時還沒有終止,程序切換就可以發生。分時依賴於定時中斷,因此,對程序是透明的。為保證CPU 分時,不需要在程式中插入額外的程式碼。

 

    排程策略也是基於依照優先順序排隊的程序。有時用複雜的演算法求出程序當前的優先順序,但最後的結果是相同的:每個程序都與一個值相關聯,這個值表示把程序如何適當地分配給CPU。在Linux 中,程序的優先順序是動態的。排程程式跟蹤程序做了些什麼,並週期性地調整它們的優先順序。在這種方式下,在較長的時間間隔內沒有使用CPU的程序,通過動態地增加它們的優先順序來提升它們。相應地,對於已經在CPU上運行了較長時間的程序,通過減少它們的優先順序來處罰它們。每個程序在建立之初有一個基本的優先順序,執行期間排程系統會動態調整它的優先順序,互動性高的任務會獲得一個高的動態優先順序,而互動性低的任務獲得一個低的動態優先順序。類程序的時間片計算如下圖所示:


   

    當談及有關排程問題時,傳統上把程序分類為“I/O 範圍(I/O-bound)”或“CPU

範圍(CPU-bound)”。前者頻繁地使用I/O 裝置,並花費很多時間等待I/O操作的完成;而後者是需要大量CPU 時間的數值計算應用程式。Linux作業系統支援多程序,程序控制塊PCB(Process ControlBlock)是系統中最為重要的資料結構之一。用來存放程序所必需的各種資訊,PCB用結構task—struct來表示,包括程序的型別、程序狀態、優先順序、時鐘資訊等。Linux系統中,程序排程操作由schedule()函式執行,這是一個只在核心態執行的函式,函式程式碼為所有程序共享。

 

   

Linux程序排程時機

   

    Linux的程序排程時機與現代作業系統中的排程時機基本一致,為了判斷是否可以執行核心的程序排程程式來排程程序,Linux中設定了程序排程標誌need—resched,當標誌為1時,可執行排程程式.通常,Linux排程時機分以下兩種情況:(1)主動排程:指顯式呼叫schedule()函式明確釋放CPU,引起新一輪排程.一般發生在當前程序狀態改變,如:程序終止、程序睡眠、程序對某些訊號處理過程中等.(2)被動排程:指不顯示呼叫schedule()函式,只是PCB中的need_resched程序排程標誌,該域置位為1將引起新的程序排程,而每當中斷處理和系統呼叫返回時,核心排程程式都會主動查詢need—resched的狀態(若置位,則主動呼叫schedule()函式。一般發生在新的程序產生時、某個程序優先順序改變時、某個程序等待的資源可用被喚醒時、當前程序時間片用完等.

 

Linux程序排程策略

  

一般來說,不同用途的作業系統的排程策略是不同的,Linux程序排程是將優先順序排程、時間片輪轉法排程、先進先出排程綜合起來應用.Linux系統中。不同型別的程序排程策略也不一樣。

1.與程序排程相關的資料結構

    每個程序都是一個動態的個體,其生命週期依次定義的資料結構為:TASK—RUNNING,TASK—INTERRUPTIBLE。TASK—UNINTERRUPTIBLE,TASK—ZOMBIE和TASK—STOPPED,一個程序在其生存期間,狀態會發生多次變化。與其資料結構相對應的即是Linux程序的狀態,分別是:執行態、等待態、暫停態和僵死態。

2.程序狀態及其轉換過程的描述

    程序建立時的狀態為不可打斷睡眠,在do—fork()結束前被父程序喚醒後。變為執行狀態,處於執行狀態的程序被移到run—queue就緒任務佇列中等待排程。適當時候由schedule0按排程演算法選中,獲得CPU,若採用輪轉法,即時,由時鐘中斷觸發timer—interrupt(),其內部呼叫schedule(),引起新一輪排程,當前程序的狀態仍處於執行狀態,因而把當前程序掛蟄Jruil—queue隊尾。獲得CPU且正在執行的程序若申請不到某資源。則呼叫sleep—on()或interruptible—sleep—on()睡眠,其task—struct程序控制塊掛到相應資源的wait—queue等待佇列如果呼叫sleep—on()。則其狀態變為不可打斷睡眠,如果呼叫interruptible—sleep—on(),則其狀態變為可打斷睡眠,Sleep—on()或interruptible—sleep—on()將呼叫schedule()函式把睡眠程序釋放。

3.程序分類和相應的程序排程策略


 

 

Linux系統中,為了高效地排程程序,將程序分威兩類:實時程序和普通程序(又稱非實時程序或一般程序),實時程序的優先順序要高於其他程序,如果一個實時程序處於可執行狀態,它將先得到執行.實時程序又有兩種策略:時間片輪轉和先進先出,在時間片輪轉策略中。每個可執行實時程序輪流執行一個時間片,而先進先出策略每個程序按各自在執行佇列中的順序執行且順序不能變化。

在Linux中,程序排程策略共定義了3種:

Linux系統中的每個程序用task,struct結構來描述,程序排程的依據是task—struct結構中的policy、priority、counter和rt—priority,PCB中設定Policy資料項,其值用於反映針對不同型別的程序而採用的排程策略。SCHED—RR和SCHED—FIFO用於實時程序。分別表示輪轉排程策略和先進先出排程策略;SCHED—OTHER表示普通程序,也按照輪轉排程策略處理。這三類排程策略均基於優先順序.PCB中設定Priority資料項,其值為普通程序的排程優先順序.普通程序的可用時間片的初始值即為該值,該值通過系統呼叫是可以改變的。PCB中設定rt~p riority資料項,其值是實時程序專用的排程優先順序,實時程序的可用時間片的初始值即為該值.該優先順序也可以用系統呼叫來修改,PCB中設定counter資料項。用於程序可用時間片時值的計數,初始值為rt—priority或Priority。程序啟動後該值隨時鐘週期遞減。

 

 

Windows程序

   

與程序排程相關的資料結構

    每個windows程序都是由一個執行體程序塊來表示的。EPROCESS塊中除了包含許多與程序有關的屬性以外,還包含和指向了許多其他的相關資料結構。例如,每個程序都有一個或多個 執行緒,這些執行緒由執行體執行緒塊來表示。執行體程序塊和相關的資料結構位於系統空間中,不過,程序塊環境是個例外,它位於程序地址空間中(因為它包含了一些需要由使用者模式程式碼來修改的資訊)。

    除了EPROCESS塊以外,windows子系統程序為每個windows程序維護了一個類似的結構。而且,windows子系統的核心模式部分有一個針對每個程序的資料結構,當一個執行緒第一次呼叫windows的USER或GDI函式時,此資料結構就會被建立。

 

下圖是一個簡化的關於程序和執行緒資料結構的框圖:


 

 

Windows 系統的程序排程方法分析

 

    Windows 中的每一個程序都是EPROCESS結構體。此結構體中除了程序的屬性之外還引用了其它一些與實現程序緊密相關的結構體。例如,每個程序都有一個或幾個執行緒,執行緒在系統中就是ETHREAD 結構體。簡要描述一下存在於這個結構體中的主要的資訊,這些資訊都是由對核心函式的研究而得知的。首先,結構體中有KPROCESS 結構體,這個結構體中又有指向這些程序的核心執行緒(KTHREAD)連結串列的指標(分配地址空間),基優先順序,在核心模式或是使用者模式執行程序的執行緒的時間,處理器affini ty(掩碼,定義了哪個處理器能執行程序的執行緒),時間片值。在ETHREAD 結構體中還存在著這樣的資訊:程序ID、父程序ID、程序映象名。

    在EPROCESS結構體中還有指向PEB的指標。ETHREAD 結構體還包含有建立時間和退出時間、程序ID 和指向EPROCESS 的指標,啟動地址,I/O請求連結串列和KTHREAD 結構體。在KTHREAD 中包含有以下資訊:核心模式和使用者模式執行緒的建立時間,指向核心堆疊基址和頂點的指標、指向服務表的指標、基優先順序與當前優先順序、指向APC的指標和指向T E B的指標。KTHREAD中包含有許多其它的資料,通過觀察這些資料可以分析出KTHREAD的結構。通過遍歷KPROCESS結構體中的ETHREAD,找到系統中當前所有的KTHREAD 結構,這個結構中的偏移量為0x124處的Affinity域(WindowsXPsp3)即為設定CPU親緣性掩碼的記憶體地址。

    Windows實現了一個優先驅動的,搶先式的排程系統——具有最高優先順序的可執行執行緒總是執行,而該執行緒可能僅限於在允許它執行的處理器上執行,這種現象稱為處理器親和性,在預設的情況下,執行緒可以在任何一個空閒的處理器上執行,但是,你可以使用windows排程函式,或者在映像頭部設定一個親和性掩碼來改變處理器親和性。

在此重點解釋CPU親緣性的概念,CPU親緣性就是指在系統中能夠將一個或多個程序或執行緒繫結到一個或多個處理器上執行,這是期待已久的特性。也就是說“: 在1號處理器上一直執行該程式”或者是“在所有的處理器上執行這些程式,而不是在0 號處理器上執行”。然後, 排程器將遵循該規則,程式僅僅執行在允許的處理器上。

    Windows 的程序排程程式碼是在它的System 程序下的,所以它不屬於任何使用者程序上下文。排程程式碼在適當的時機會切換程序上下文,這裡的切換程序上下文是指程序環境的切換, 包括記憶體中的可執行程式, 提供程式執行的各種資源.程序擁有虛擬的地址空間,可執行程式碼, 資料, 物件控制代碼集, 環境變數, 基礎優先順序, 以及最大最小工作集等的切換。

    而Windows最小的排程單位是執行緒, 只有執行緒才是真正的執行體,程序只是執行緒的容器。Windows調程式在時間片到期,或有切換執行緒指令執行(如Sleep,KeWaitForSingleObject 等函式)時, 將會從程序執行緒佇列中找到下一個要排程的執行緒執行體,並裝入到KPCR(Kernel 's Processor Control Region ,核心程序控制區域) 結構中,CPU 根據KPCR結構中的KPRCB 結構執行執行緒執行體程式碼。

    而在多核CPU下,當Windows排程程式碼執行時,從當前要排程執行的KTHREAD結構中取出Affinity,並與當前PC 機上的硬體配置資料中的CPU 掩碼作與操作,結果寫入到指定的CPU,例如雙核CPU 的裝置掩碼為0x03,如果當前KTHREAD裡的Affinity 為0x01,那麼0x01&0x03=0x01,這樣執行體執行緒會被裝入CPU1的KPRCB 結構中得以執行,排程程式不會把這個執行緒交給CPU2 去執行。此過程如圖2 所示。這就是為執行緒選擇指定CPU 核的原理。

    小結:程序排程策略的選擇對整個系統性能有至關重要的影響,一個好的排程演算法應該考慮很多方面:公平、有效、響應時間、週轉時間、系統吞吐量等等。但這些因素之間又是相互矛盾的,最終的取捨根據系統要達到的目標而定,同時我們也可以看出多程序的管理是~種非常複雜的併發程式設計.每個程序的狀態不僅由其自身決定,而且還要受諸多外在因素的影響.而在此基礎上的程序排程,為了保證作業系統的穩定性、提高效率和增加靈活性,還必須採用很多方法,這些都是值得我們去研究和探討的:。

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述