當前位置:編程學習大全網 - 網絡軟體 - Linux 進程管理之進程調度與切換

Linux 進程管理之進程調度與切換

我們知道,進程運行需要各種各樣的系統資源,如內存、文件、打印機和最

寶貴的 CPU 等,所以說,調度的實質就是資源的分配。系統通過不同的調度算法(Scheduling Algorithm)來實現這種資源的分配。通常來說,選擇什麽樣的調度算法取決於資源分配的策略(Scheduling Policy)。

有關調度相關的結構保存在 task_struct 中,如下:

active_mm 是為內核線程而引入的,因為內核線程沒有自己的地址空間,為了讓內核線程與普通進程具有統壹的上下文切換方式,當內核線程進行上下文切換時,讓切換進來的線程的 active_mm 指向剛被調度出去的進程的 active_mm(如果進程的mm 域不為空,則其 active_mm 域與 mm 域相同)。

在 linux 2.6 中 sched_class 表示該進程所屬的調度器類有3種:

進程的調度策略有5種,用戶可以調用調度器裏不同的調度策略:

在每個 CPU 中都有壹個自身的運行隊列 rq,每個活動進程只出現在壹個運行隊列中,在多個 CPU 上同時運行壹個進程是不可能的。

運行隊列是使用如下結構實現的:

tast 作為調度實體加入到 CPU 中的調度隊列中。

系統中所有的運行隊列都在 runqueues 數組中,該數組的每個元素分別對應於系統中的壹個 CPU。在單處理器系統中,由於只需要壹個就緒隊列,因此數組只有壹個元素。

內核也定義了壹下便利的宏,其含義很明顯。

Linux、c/c++服務器開發篇-------我們來聊聊進程的那些事

Linux內核 進程間通信組件的實現

學習地址:C/C++Linux服務器開發/後臺架構師零聲教育-學習視頻教程-騰訊課堂

需要C/C++ Linux服務器架構師學習資料加qun812855908獲取(資料包括 C/C++,Linux,golang技術,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK,ffmpeg 等),免費分享

在分析調度流程之前,我們先來看在什麽情況下要執行調度程序,我們把這種情況叫做調度時機。

Linux 調度時機主要有。

時機1,進程要調用 sleep() 或 exit() 等函數進行狀態轉換,這些函數會主動調用調度程序進行進程調度。

時機2,由於進程的時間片是由時鐘中斷來更新的,因此,這種情況和時機4 是壹樣的。

時機3,當設備驅動程序執行長而重復的任務時,直接調用調度程序。在每次反復循環中,驅動程序都檢查 need_resched 的值,如果必要,則調用調度程序 schedule() 主動放棄 CPU。

時機4 , 如前所述, 不管是從中斷、異常還是系統調用返回, 最終都調用 ret_from_sys_call(),由這個函數進行調度標誌的檢測,如果必要,則調用調用調度程序。那麽,為什麽從系統調用返回時要調用調度程序呢?這當然是從效率考慮。從系統調用返回意味著要離開內核態而返回到用戶態,而狀態的轉換要花費壹定的時間,因此,在返回到用戶態前,系統把在內核態該處理的事全部做完。

Linux 的調度程序是壹個叫 Schedule() 的函數,這個函數來決定是否要進行進程的切換,如果要切換的話,切換到哪個進程等。

從代碼分析來看,Schedule 主要完成了2個功能:

進程上下文切換包括進程的地址空間的切換和執行環境的切換。

對於 switch_mm 處理,關鍵的壹步就是它將新進程頁面目錄的起始物理地址裝入到寄存器 CR3 中。CR3 寄存器總是指向當前進程的頁面目錄。

switch_to 把寄存器中的值比如esp等存放到進程thread結構中,保存現場壹邊後續恢復,同時調用 __switch_to 完成了堆棧的切換。

在進程的 task_struct 結構中有個重要的成分 thread,它本身是壹個數據結構 thread_struct, 裏面記錄著進程在切換時的(系統空間)堆棧指針,取指令地址(也就是“返回地址”)等關鍵性的信息。

關於__switch_to 的工作就是處理 TSS (任務狀態段)。

TSS 全稱task state segment,是指在操作系統進程管理的過程中,任務(進程)切換時的任務現場信息。

linux 為每壹個 CPU 提供壹個 TSS 段,並且在 TR 寄存器中保存該段。

linux 中之所以為每壹個 CPU 提供壹個 TSS 段,而不是為每個進程提供壹個TSS 段,主要原因是 TR 寄存器永遠指向它,在任務切換的適合不必切換 TR 寄存器,從而減小開銷。

在從用戶態切換到內核態時,可以通過獲取 TSS 段中的 esp0 來獲取當前進程的內核棧 棧頂指針,從而可以保存用戶態的 cs,esp,eip 等上下文。

TSS 在任務切換過程中起著重要作用,通過它實現任務的掛起和恢復。所謂任務切換是指,掛起當前正在執行的任務,恢復或啟動另壹任務的執行。

在任務切換過程中,首先,處理器中各寄存器的當前值被自動保存到 TR(任務寄存器)所指定的任務的 TSS 中;然後,下壹任務的 TSS 被裝入 TR;最後,從 TR 所指定的 TSS 中取出各寄存器的值送到處理器的各寄存器中。由此可見,通過在 TSS 中保存任務現場各寄存器狀態的完整映象,實現任務的切換。

因此,__switch_to 核心內容就是將 TSS 中的內核空間(0級)堆棧指針換成 next->esp0。這是因為 CPU 在穿越中斷門或者陷阱門時要根據新的運行級別從TSS中取得進程在系統空間的堆棧指針。

thread_struct.esp0 指向進程的系統空間堆棧的頂端。當壹個進程被調度運行時,內核會將這個變量寫入 TSS 的 esp0 字段,表示這個進程進入0級運行時其堆棧的位置。換句話說,進程的 thread_struct 結構中的 esp0 保存著其系統空間堆棧指針。當進程穿過中斷門、陷阱門或者調用門進入系統空間時,處理器會從這裏恢復期系統空間棧。

由於棧中變量的訪問依賴的是段、頁、和 esp、ebp 等這些寄存器,所以當段、頁、寄存器切換完以後,棧中的變量就可以被訪問了。

因此 switch_to 完成了進程堆棧的切換,由於被切進的進程各個寄存器的信息已完成切換,因此 next 進程得以執行指令運行。

由於 A 進程在調用 switch_to 完成了與 B 進程堆棧的切換,也即是寄存器中的值都是 B 的,所以 A 進程在 switch_to 執行完後,A停止運行,B開始運行,當過壹段時間又把 A 進程切進去後,A 開始從switch_to 後面的代碼開始執行。

schedule 的調用流程如下:

  • 上一篇:轉轉怎麽看買家買保險了沒
  • 下一篇:現在有沒有預測大盤比較準的博客啊?
  • copyright 2024編程學習大全網