操作系統如何介入到我的程序的?

假如我寫了一個沒有用任何庫的C語言程序,程序內容就是循環,讓他能達到運行十幾秒。那麼為什麼我程序在運行的時候,我仍然能夠切換出去玩其他的。這裡有一個關鍵,我的程序並沒有調用操作系統的代碼,而且我的程序一直在控制CPU,操作系統沒有CPU時間,他是如何下指令,讓我能夠切換出當前的循環程序的?


時鐘中斷

即使你寫個死循環,也不會一直佔cpu,每次中斷都會強行打斷執行


在Windows操作系統下,你的程序會在具有獨立地址空間的進程中運行,每一個進程都至少有一個線程,你的代碼就是在這個線程里執行的。至於切換,這是操作系統的功能,就是一般意義上的線程切換,操作系統會根據線程的優先順序為每個線程分配時間片,切換到其它線程時會進行上下文切換,一些重要的數據結構,包括內存信息以及相關寄存器的值會被保存下來,當線程切換到你的程序時,這些信息會被重新恢復到相應位置上。對於你來說,這一切都是透明的,你其實不需要關注太多。


按照題主說的場景,結合現在主流CPU的水準,還不到分析內核進程調度的程度。因為「程序一直在控制CPU,操作系統沒有CPU時間」,這個其實是不準確的。

現在的大部分普通PC的CPU至少都是雙核,一個死循環進程最多只會佔滿其中一個核心,並不能完全獨佔整個CPU。其餘的核心還空閑著,操作系統以及其它程序還可以在那些核心上愉快的運行。所以即使不存在進程調度切換什麼的,死循環程序在運行的時候,你仍然能夠玩其他的。

如果在一顆不知道多少年前的古董級單核單線程CPU上跑一個死循環進程,或者在雙核四線程CPU上同時跑四個死循環進程,那麼就真的會卡出翔了。但雖然卡出翔,但是操作系統仍然沒有徹底失去響應,滑鼠還能移動,只是卡得跟幻燈片一樣。

這種情況下,操作系統能夠介入死循環用戶進程的關鍵是,處理器硬體層面每隔固定的N毫秒會主動發出一次時鐘中斷,導致當前CPU核心上正在瘋狂死循環的進程被暫停,切換成操作系統的相關代碼。但是總體上操作系統以及其它軟體進程並不會佔用太多CPU時間,所以大部分CPU時間都是分配給死循環進程在跑的。


操作系統是父母,應用程序是子女。其基本關係就是,子女是大爺,「衣來伸手,飯來張口」,父母屬於擦屁股的角色。父母是否將所有的資源給子女,取決於是獨生子女還是有很多兄弟姐妹。當然,父母是當家的。

也就是分2種情況。單任務與多任務

1單任務:獨生子女。操作系統將全部CPU資源給應用程序,應用程序執行題中的循環,循環結束後將CPU資源交換給應用程序。如果應用程序的代碼是死循環,操作系統是否會忠實的一直執行下去,取決於操作系統。CPU有時鐘,會產生中斷,如果在這個中斷中採取控制,是可以強行結束應用程序的。

2多任務:多個子女。將CPU資源分配給多個應用程序,對於單CPU而言,將CPU資源按極其小的時間分片給應用程序,實現多任務。類似於動畫的原理,將幾張圖片連續切換,形成動的效果,但每個時間都只看了一張圖片。

對於操作系統的作用,應用程序說:要內存,要使用顯示器,要CPU運行時間……這些都是由操作系統來實現。應用程序一句話,操作系統忙半天。


一個線程在創建的時候,內核會為其創建一個內核對象,在該內核對象中有一個成員變數叫做上下文結構,其中存儲的是CPU最後運行該線程時CPU寄存器的值,這樣當該線程再次被調度運行的時候,CPU就讀取上下文結構中的數據,實現繼續對該線程執行。

大體的調度過程是:CPU每隔20ms左右就會檢查一遍所有的線程內核對象,通過其結構中的暫停計數器的值,判斷是否可被調度,如果可以被調度,則載入該線程,讀取其上下文結構,繼續執行該線程未完的代碼。

如果所有運行的線程都具有相同的優先順序,那麼線程調度的過程就如上面所示。但是由於windows操作系統是一個搶先式的操作系統,因此任何一個線程都有可能在時間片未到的時候被其他的線程打斷。

樓主如果覺得自己彙編不錯,數據結構不差,c很好的話可以 參考Linux內核源碼。


只是表面上你的程序是在連續執行,實際你的程序每秒最少都會被中斷執行幾十次上百次,由操作系統根據優先順序等條件來決定你的程序每秒會佔用多少cpu時間,每次你的程序中斷cpu都會把當前寄存器儲存,保存上下文,然後切換到其它程序執行,因為速度非常快,所以你感覺是在連續執行


樓主看看操作系統的進程,線程,調度演算法就能知道答案了。


推薦閱讀:

如何學python-第八課 流程式控制制-For,While,循環語句,初見『函數』
從硬碟里翻出來2010年寫的帶IntelliSense編輯器
eval 之源
邏輯表達式的短路是如何實現的?
for 循環為什麼不支持小數?

TAG:編程語言 | 編程 | 彙編語言 | 編程比賽 | 電子計算機 |