一、優先級和進程優先級
1.1什么是優先級
優先級就是獲取某種資源的先后順序,比如打飯時排隊:排隊就是在確認優先級
1.2為什么要有優先級
本質上其實是目標資源相對于需求者來說比較少,如CPU,磁盤,顯示器,鍵盤等相對于進程來說并不充足
1.3優先級與權限有類似的地方,他們的區別是什么
優先級:能使用資源,決定誰先誰后問題
權限:決定能不能使用資源的問題
1.4進程優先級與競爭性的體現
1.4.1進程優先級競爭的資源
優先級的存在是因為資源較少,需要排順序來競爭資源分配,那么對于進程優先級來說競爭的資源是什么呢?
競爭的是CPU資源
1.4.2競爭性的體現
競爭性的原因:資源稀缺
系統中進程數目很多,但是CPU很少,進程之間就有了競爭屬性
為了更高效地完成任務,更合理地競爭資源,便有了進程優先級
二、進程優先級是怎么實現的
2.1用戶名和與之強相關的UID
2.1.1UID是什么
在Linux下,會為每個用戶維護一個對應的UID整形值來代表用戶名所對應地字符串
可以使用ls -n來查看
可以發現在-n選項下,用戶名 my_normal對應的字符串被替換成了整數1000?
2.1.2為什么要有UID
UID標識了用戶ID,代表進程是哪一個用戶啟動的
①Linux下一切皆文件,每個文件都會記錄自己的擁有者,所屬組以及對應的權限
②Linux下所有操作都是進程來完成,進程也屬于文件,自然要記錄“擁有者”,即:“誰(哪個用戶)啟動的我”
總而言之,進程通過記錄“誰啟動的我”來判斷自身是否屬于文件的擁有者/所屬組,以此確定是否有權限進行一些操作,這就是權限控制實現的底層原理,也是UID的意義
2.2task_struct中優先級屬性的實現原理
task_struct中的優先級屬性是通過特定的幾個int類型的變量來表示優先級的(優先級數字越小,代表優先級越高)
查看優先級:
可以通過ps -la指令查看所有自己創建的進程的詳細信息,包括其優先級
其中:PRI和NI對應的就是優先級屬性
PRI:最終優先級
NI:是nice(細微)的簡寫,代表優先級的修正數據
最終優先級=默認PRI(例子中為80)+NI
2.3如何修改進程優先級(注:此功能不是高頻使用的,且不建議修改)
修改進程優先級使用的是top指令的一個功能:
進入top指令->輸入r->輸入PID->輸入nice值
(注:OS禁止頻繁修改優先級,同時UID對應用戶沒有權限的話也不允許修改)
原進程:
top的r功能:
?輸入一個大于等于19的數,修改后:
再輸入一個小于等于-20的數,觸發OS保護機制,不允許連續修改進程優先級:
?切換為root賬戶再修改:
綜上,NI值有范圍限制,在[-20,19]之間 ,共40個數字
2.3補:為什么要把nice值設置在一個可控范圍內?為什么是[-20,19]?
分時OS的進程調度需要遵循盡量公平的原則,如果有一個進程優先級特別高,會破壞這一公平性
2.4進程切換
2.4.1時間片的概念與時間片對于進程有什么影響
①時間片
Linux基于時間片進行輪轉調度,一個進程的時間到了它的時間片,進程切換
②時間片對于進程的影響
時間片到了,這一進程并不一定跑完,因此進程需要保存自己的運行狀態,在任何地方都可以被重新調度
2.4.2結合實際生活中的例子理解輪轉調度
就像在學校轉而去當兵入伍,確定入伍名額需要向學校申請保留學籍
退伍后,需要向學校申請恢復學籍
其中保留學籍的目的是留存歷史的學習痕跡,保留不是目的,而是手段,未來的恢復才是目的
類比起來
①學生就像進程,CPU就像學校,部隊就像OS中,在學校學習的時間就是時間片
②保留學籍就像保存上下文數據
③恢復學籍就像回復上下文數據
2.4.3切換過程和理解
①進程在運行的過程中,會有許多臨時數據在CPU的寄存器中保存,CPU內部有多個寄存器,我們稱之為“一套寄存器”
CPU如何得知當前運行到代碼中哪一行了呢?
是依靠pc指針與ir指針:
磁盤中的代碼和數據加載到內存中,在這段內存空間中,每一句代碼都有自己的地址
此時的eip寄存器(又名pc指針,i是instruction的簡寫,意思為指令;p是point的簡寫,意思是指針)存儲當前正在執行指令的下一條指令的地址
ir寄存器:指令寄存器,保存的是當前從內存加載到CPU中,正在執行的指令
②CPU內部寄存器中的一系列數據,是進程執行時的瞬時狀態信息數據(又名上下文數據)
2.4.3補:寄存器!=寄存器里的上下文數據,還有其他內容
2.4.4進程切換的核心:上下文數據的保存和恢復
進程切換的核心就是進程上下文數據的保存和恢復,一個可執行程序開始運行的過程:
①pc中存main函數的地址,
②之后把執行加載到ir中,更新pc值
③ir將指令交給CPU中一個控制器來執行,執行結束進行下一行代碼的讀取
之后運行進程一的時間片,到時間后換到進程二,以此類推
假如這個過程不保護(不保存上下文數據):
進程一運行結束,回到調度隊列,CPU中pc指針讀取了進程二的首語句,會把原來進程一的痕跡覆蓋;下一次輪到進程一執行,找不到上次的痕跡,無法繼續運行
則無法完成調度與切換
做保護:
會在CPU外的某個位置將進程一的上下文數據保存起來,再進行pc指針讀取進程二首語句
進程切走:將相關寄存器數據保存起來
進程切回:將歷史保存的寄存器數據恢復到寄存器中
2.4.5進程切換過程中,CPU寄存器被共享使用
每個進程都有自己的上下文數據,這些上下文數據需要加載到CPU寄存器內部來使用,而CPU寄存器只有一套,所以CPU被多個進程共享使用
2.4.6每個進程的上下文數據究竟存儲在哪里
現在電腦對于進程上下文數據的保護體系已經十分完善了,涉及到多個位置
但我們可以理解為上下文數據保存在內存的PCB中
從源碼中可以看出端倪:
在task_struct中有一個tss的定義,而它是這個:
?所以進程的上下文數據保存在任務狀態段(TSS) 的結構體中