CPU 上下文切換是什麼

2022-08-05 13:21:19 字數 1745 閱讀 5351

linux 是一個多工作業系統,它支援遠大於 cpu 數量的任務同時執行。當然,這些任務實際上並不是真的在同時執行,而是因為系統在很短的時間內,將 cpu 輪流分配給它們,造成多工同時執行的錯覺

而在每個任務執行前,cpu 都需要知道任務從**載入、又從**開始執行,也就是說,需要系統事先幫它設定好 cpu 暫存器和程式計數器(program counter,pc)。cpu 暫存器,是 cpu 內建的容量小、但速度極快的記憶體。而程式計數器,則是用來儲存 cpu 正在執行的指令位置、或者即將執行的下一條指令位置。它們都是 cpu 在執行任何任務前,必須的依賴環境,因此也被叫做 cpu 上下文。

cpu 上下文切換,就是先把前一個任務的 cpu 上下文(也就是 cpu 暫存器和程式計數器)儲存起來,然後載入新任務的上下文到這些暫存器和程式計數器,最後再跳轉到程式計數器所指的新位置,執行新任務。而這些儲存下來的上下文,會儲存在系統核心中,並在任務重新排程執行時再次載入進來。這樣就能保證任務原來的狀態不受影響,讓任務看起來還是連續執行。

據任務的不同,cpu 的上下文切換就可以分為幾個不同的場景,也就是程序上下文切換、執行緒上下文切換以及中斷上下文切換。

程序上下文切換linux 按照特權等級,把程序的執行空間分為核心空間和使用者空間,分別對應著下圖中, cpu 特權等級的 ring 0 和 ring 3。核心空間(ring 0)具有最高許可權,可以直接訪問所有資源;使用者空間(ring 3)只能訪問受限資源,不能直接訪問記憶體等硬體裝置,必須通過系統呼叫陷入到核心中,才能訪問這些特權資源。

程序既可以在使用者空間執行,又可以在核心空間中執行。程序在使用者空間執行時,被稱為程序的使用者態,而陷入核心空間的時候,被稱為程序的核心態。從使用者態到核心態的轉變,需要通過系統呼叫來完成。比如,當我們檢視檔案內容時,就需要多次系統呼叫來完成:首先呼叫 open() 開啟檔案,然後呼叫 read() 讀取檔案內容,並呼叫 write() 將內容寫到標準輸出,最後再呼叫 close() 關閉檔案。

cpu 暫存器裡原來使用者態的指令位置,需要先儲存起來。接著,為了執行核心態**,cpu 暫存器需要更新為核心態指令的新位置。最後才是跳轉到核心態執行核心任務。而系統呼叫結束後,cpu 暫存器需要恢復原來儲存的使用者態,然後再切換到使用者空間,繼續執行程序。所以,一次系統呼叫的過程,其實是發生了兩次 cpu 上下文切換。

中斷上下文切換除了前面兩種上下文切換,還有一個場景也會切換 cpu 上下文,那就是中斷。為了快速響應硬體的事件,中斷處理會打斷程序的正常排程和執行,轉而呼叫中斷處理程式,響應裝置事件。而在打斷其他程序時,就需要將程序當前的狀態儲存下來,這樣在中斷結束後,程序仍然可以從原來的狀態恢復執行。跟程序上下文不同,中斷上下文切換並不涉及到程序的使用者態。所以,即便中斷過程打斷了一個正處在使用者態的程序,也不需要儲存和恢復這個程序的虛擬記憶體、全域性變數等使用者態資源。中斷上下文,其實只包括核心態中斷服務程式執行所必需的狀態,包括 cpu 暫存器、核心堆疊、硬體中斷引數等。對同一個 cpu 來說,中斷處理比程序擁有更高的優先順序,所以中斷上下文切換並不會與程序上下文切換同時發生。同樣道理,由於中斷會打斷正常程序的排程和執行,所以大部分中斷處理程式都短小精悍,以便儘可能快的執行結束。另外,跟程序上下文切換一樣,中斷上下文切換也需要消耗 cpu,切換次數過多也會耗費大量的 cpu,甚至嚴重降低系統的整體效能。所以,當你發現中斷次數過多時,就需要注意去排查它是否會給你的系統帶來嚴重的效能問題。