CPU 空閒時在幹嘛?

2021-10-21 20:13:53 字數 4583 閱讀 1751

人空閒時會發呆會無聊,計算機呢?

假設你正在用計算機瀏覽網頁,當網頁載入完成後你開始閱讀,此時你沒有移動滑鼠,沒有敲擊鍵盤,也沒有網路通訊,那麼你的計算機此時在幹嘛?

有的同學可能會覺得這個問題很簡單,但實際上,這個問題涉及從硬體到軟體、從 cpu 到作業系統等一系列環節,理解了這個問題你就能明白作業系統是如何工作的了。

如果此時你正在計算機旁,並且安裝有 windows 或者 linux ,你可以立刻看到自己的計算機 cpu 使用率是多少。

這是博主的一台安裝有 win10 的筆記本:

可以看到大部分情況下 cpu 利用率很低,也就在 8% 左右,而且開啟了 283 個程序,這麼多程序基本上無所事事都在等待某個特定事件來喚醒自己,就好比你寫了乙個列印使用者輸入的程式,如果使用者一直不按鍵盤,那麼你的程序就處於這種狀態。

有的同學可能會想也就你的比較空閒吧,實際上大部分個人計算機 cpu 使用率都差不多這樣(排除掉看電影、玩遊戲等場景),如果你的使用率總是很高,風扇一直在嗡嗡的轉,那麼不是軟體 bug 就有可能是病毒。。。

那麼有的同學可能會問,剩下的 cpu 時間都去**了?

這個問題也很簡單,還是以 win10 為例,開啟任務管理器,找到 「詳細資訊」 這一欄,你會發現有乙個 「系統空閒程序」,其 cpu 使用率達到了 99%,正是這個程序消耗了幾乎所有的 cpu 時間。

那麼為什麼存在這樣乙個程序呢?以及這個程序什麼時候開始執行呢?

這就要從作業系統說起了。

程式設計師寫完**後開始編譯,這時編譯器將普通的文字檔案翻譯成二進位制可執行檔案,此時的程式依然是儲存在磁碟上的檔案,和普通沒有本質區別。

但此時不一樣的是,該檔案是可執行檔案,也就是說作業系統開始 「懂得」 這種檔案,所謂 「懂得」 是指作業系統可以識別、解析、載入,因此必定有某種類似協議的規範,這樣編譯器按照這種協議生成可執行檔案,作業系統就能載入了。

在 linux 下可執行檔案格式為 elf ,在 windows 下是 exe 。

此時雖然作業系統可以識別可執行程式,但如果你不去雙擊一下(或者在linux下執行相應命令)的依然和作業系統沒有半毛錢關係。

但是當你執行可執行程式時魔法就出現了。

此時作業系統開始將可執行檔案載入到記憶體,解析出**段、資料段等,並為這個程式建立執行時需要的堆區棧區等記憶體區域,此時這個程式在記憶體中就是這樣了:

最後,根據可執行檔案的內容,作業系統知道該程式應該執行的第一條機器指令是什麼,並將其告訴 cpu ,cpu 從該程式的第一條指令開始執行,程式就這樣執行起來了。

乙個在記憶體中執行起來的程式顯然和儲存在磁碟上的二進位制檔案是不一樣的,總的有個名字吧,根據「弄不懂原則」,這個名字就叫程序,英文名叫做process。

我們把乙個執行起來的程式叫做程序,這就是程序的由來

此時作業系統開始掌管程序,現在程序已經有了,那麼作業系統是怎麼管理程序的呢?

銀行想必大家都去過,實際上如果你仔細觀察的話銀行的辦事大廳就能體現出作業系統最核心的程序管理與排程。

首先大家去銀行都要排隊,類似的,程序在作業系統中也是通過佇列來管理的。

同時銀行還按照客戶的重要程度劃分了優先順序,大部分都是普通客戶;但當你在這家銀行存上幾個億時就能公升級為 vip 客戶,優先順序最高,每次去銀行都不用排隊,優先辦理你的業務。

類似的,作業系統也會為程序劃分優先順序,作業系統會根據程序優先順序將其放到相應的佇列中供排程器排程。

現在準備工作已經就緒。

接下來的問題就是作業系統如何確定是否還有程序需要執行。

從上一節我們知道,實際上作業系統是用佇列來管理程序的,那麼很顯然,如果佇列已經為空,那麼說明此時作業系統內部沒有程序需要執行,這是 cpu 就空閒下來了,此時,我們需要做點什麼,就像這樣:

if (queue.empty())
這些編寫核心**雖然簡單,但核心中到處充斥著 if 這種異常處理的語句,這會讓**看起來一團糟,因此更好的設計是沒有異常,那麼怎樣才能沒有異常呢?

很簡單,那就是讓佇列永遠不會空,這樣排程器永遠能從佇列中找到乙個可供執行的程序。

而這也是為什麼鍊錶中通常會有哨兵節點的原因,就是為了避免各種判空,這樣既容易出錯也會讓**一團糟。

就這樣,核心設計者建立了乙個叫做空閒任務的程序,這個程序就是windows 下的我們最開始看到的「系統空閒程序」,在 linux 下就是第 0號程序。

當其它程序都處於不可執行狀態時,排程器就從佇列中取出空閒程序執行,顯然,空閒程序永遠處於就緒狀態,且優先順序最低

既然我們已經知道了,當系統無所事事後開始執行空閒程序,那麼這個空閒程序到底在幹嘛呢?

這就需要硬體來幫忙了。

在計算機系統中,一切最終都要靠 cpu 來驅動,cpu 才是那個真正幹活的。

原來,cpu 設計者早就考慮到系統會存在空閒的可能,因此設計了一條機器指令,這個機器指令就是 halt 指令,停止的意思。

這條指令會讓部分cpu進入休眠狀態,從而極大減少對電力的消耗,通常這條指令也被放到迴圈中執行,原因也很簡單,就是要維持這種休眠狀態。

值得注意的是,halt 指令是特權指令,也就是說只有在核心態下 cpu 才可以執行這條指令,程式設計師寫的應用都執行在使用者態,因此你沒有辦法在使用者態讓 cpu 去執行這條指令。

此外,不要把程序掛起和 halt 指令混淆,當我們呼叫 sleep 之類函式時,暫停執行的只是程序,此時如果還有其它程序可以執行那麼 cpu 是不會空閒下來的,當 cpu 開始執行halt指令時就意味著系統中所有程序都已經暫停執行。

現在我們有了 halt 機器指令,同時有乙個迴圈來不停的執行 halt 指令,這樣空閒任務程序的實際上就已經實現了,其本質上就是這個不斷執行 halt 指令的迴圈,大功告成。

這樣,當排程器在沒有其它程序可供排程時就開始執行空間程序,也就是在迴圈中不斷的執行 halt 指令,此時 cpu 開始進入低功耗狀態。

在 linux 核心中,這段**是這樣寫的:

while (1) }
其中 cpuidle_idle_call函式最終會執行 halt 指令,注意,這裡刪掉了很多細節,只保留最核心**,實際上 linux 核心在實現空閒程序時還要考慮很多很多,不同型別的 cpu 可能會有深睡眠淺睡眠之類,作業系統必須要**出系統可能的空閒時長並以此判斷要進入哪種休眠等等,但這並不是我們關注的重點。

總的來說,這就是計算機系統空閒時 cpu 在幹嘛,就是在執行這一段**,本質上就是 cpu 在執行 halt 指令。

實際上,對於個人計算機來說,halt 可能是 cpu 執行最多的一條指令,全世界的 cpu 大部分時間都用在這條指令上了,是不是很奇怪。

更奇怪的來了,有的同學可能已經注意到了,上面的迴圈可以是乙個while(1) 死迴圈,而且這個迴圈裡沒有break語句,也沒有return,那麼作業系統是怎樣跳出這個迴圈的呢?我們在後續文章中詳細講解。

cpu 空閒時執行特定的 halt 指令,這看上去是乙個很簡單的問題,但實際上由於 halt 是特權指令,只有作業系統才可以去執行,因此 cpu 空閒時執行 halt 指令就變成了軟體和硬體相結合的問題。

作業系統必須判斷什麼情況下系統是空閒的,這涉及到程序管理和程序排程,同時,halt 指令其實是放到了乙個 while 死迴圈中,作業系統必須有辦法能跳出迴圈,所以,cpu 空閒時執行 halt 指令並沒有看上去那麼簡單。

參考資料

什麼是程式?

程序排程器是如何實現的?

程式設計師應如何理解 cpu ?

看完這篇還不懂執行緒與執行緒池你來打我

CPU 空閒時在幹嘛?

人空閒時會發呆會無聊,計算機呢?假設你正在用計算機瀏覽網頁,當網頁載入完成後你開始閱讀,此時你沒有移動滑鼠,沒有敲擊鍵盤,也沒有網路通訊,那麼你的計算機此時在幹嘛?有的同學可能會覺得這個問題很簡單,但實際上,這個問題涉及從硬體到軟體 從 cpu 到作業系統等一系列環節,理解了這個問題你就能明白作業系...

CPU 空閒時在幹嘛?

人空閒時會發呆會無聊,計算機呢?假設你正在用計算機瀏覽網頁,當網頁載入完成後你開始閱讀,此時你沒有移動滑鼠,沒有敲擊鍵盤,也沒有網路通訊,那麼你的計算機此時在幹嘛?有的同學可能會覺得這個問題很簡單,但實際上,這個問題涉及從硬體到軟體 從 cpu 到作業系統等一系列環節,理解了這個問題你就能明白作業系...

如何打發空閒時間

1從事軟體工作,經常會遇到一陣松一陣忙的情況。忙的時候有事做,松的時候就會產生無聊的感覺。這段時間真不知道如何打發,因為在這段時間內,不知道老大什麼時候下乙個任務給你做。若把這 段時間用來學習,感覺學習時間太短,學習不到什麼。我們是不是應該具備一種能力,用一天的時間或幾個小時的時間掌握一種技術。但這...