1.馮諾依曼體系結構---存儲程序
馮諾依曼的體系結構:存儲器爲核心,所有操作都通過內存來連接
比如寫文檔的時候:鍵盤編輯輸入內容->加載到內存上->cpu處理調度->控制顯示屏輸出內容
2.操作系統--統籌管理計算機的軟硬件資源
如何管理進程?------先描述、後組織
小常識---操作系統通過對驅動程序的管理實現對硬件資源的管理
內存介質具有易失性、硬盤是持久化介質
- 1-作用:
a.通過驅動程序與硬件交互,對計算機資源進行統籌管理
b.給用戶提供良好的操作環境
- 2-什麼是管理?
------先描述管理對象、再對被管理對象進行操作
- 3-什麼是系統調用?
-----操作系統給用戶提供的對計算機進行操作的接口
- 4-什麼是庫函數?
-----因爲系統調用的複雜性,將部分系統調用進行組合封裝,形成了庫
- 5系統調用與庫函數的關係?
-----庫函數是對系統調用的封裝,是上下級調用關係
3.進程概念
- 1-什麼是進程?-----進程控制塊(PCB-process control block)
-----簡單來說,進程就是運行中的程序
-----在內核中用task_struct這個結構體來形容進程,操作系統通過分配pcb對進程進行描述和管理
task_struct{
內存指針 //程序代碼和進程相關數據的指針
程序計數器 //程序中即將被執行的下一條指令的地址
上下文數據 //進程執行時處理器的寄存器中的數據
標識符---pid //與進程相關的唯一標識符,用來區別正在執行的進程和其他進程
進程狀態 //描述進程的狀態,因爲進程有掛起,阻塞,運行等好幾個狀態,
//所以都有個標識符來記錄進程的執行狀態
優先級 //如果有好幾個進程正在執行,就涉及到進程被執行的先後順序的問題,
//這和進程優先級這個標識符有關
IO狀態信息 //包括顯示的I/O請求,分配給進程的I/O設備和被進程使用的文件列表等
記賬信息--運行時長 //包括處理器的時間總和,記賬號等等
}
ps:可執行程序加載到內存上,CPU通過pcb調度進程
- 2-如何查看進程?---使用ps命令
/* 通過pid查看進程 */
ps -ef | grep pid >>>> -e 顯示所有進程 -f 全格式顯示
ps -aux | grep pid
eg:ls -l /proc/pid // 查看一個進程,/proc目錄下存放的是進程信息
查看進程信息:通過/proc查看
- 3-如何查看進程標識符?
----通過調用函數pid_t getpid()獲取調用進程的pid
4.進程創建
--fork函數通過複製調用進程(父進程)的pcb來創建一個新的進程(子進程)
- 1-父子進程的pcb相同,如何分辨父子進程?
---通過fork函數的返回值:
-1 “創建失敗”
0 “子進程:返回0”
>0 "父進程:返回子進程的pid”
/* 通過fork()創建子進程 */
int pid = fork();
if (pid < 0) {
// 複製出錯
perror("fork error");
exit(-1);
} else if (pid == 0) {
// 子進程
} else {
// 父進程
}
- 2-創建子進程的意義?
----分攤壓力、程序替換
- 3-父子進程代碼共享,數據獨有
因爲fork()通過複製父進程來創建一個子進程,所以父子進程具有相同的pcb,但是各自的數據不同,通過進程的虛擬地址空間映射到不同的物理內存上
5.進程狀態
- 1-什麼是進程的狀態?
-----進程狀態反映進程執行過程的變化,隨着進程的執行和外界條件的變化而轉換。
- 2-類別:
---運行態(R)、TASK_RUNNING
可中斷睡眠態(S)、TASK_INTERRUPTIBLE
不可中斷睡眠態(D)、TASK_UNINTERRUPTIBLE
停止態(T)、TASK_STOPPED
僵死態(Z)、EXIT_ZOMBIE
不常見-- 死亡態(X)、EXIT_DEAD
追蹤態(t)、TASK_TRACED
---[ctrl]+c>>>中斷 [ctrl]+z>>>變爲停止態 kill pid>>>終止(Terminated)
---停止態的進程通過 kill -9 pid 強行終止
- 3-殭屍進程
---處於僵死態的進程
---產生原因:子進程先於父進程退出,操作系統保留子進程的退出信息於pcb中返回給父進程,但並不釋放子進程的資源,導致子進程退出,但資源未完全釋放,處於僵死態
---危害:資源泄露、創建進程失敗(一個進程可以創建的進程是有限個的)
---解決方案:操作系統返還子進程的退出信息給其父進程,但是當父進程也退出後,這個退出信息就失效成爲無意義消息,因此通過kill掉父進程,釋放子進程未釋放的資源
---如何避免:進程等待--wait()
- 4-孤兒進程
---產生原因:父進程先於子進程退出,子進程成爲孤兒進程,運行在後臺,父進程成爲1號進程
- 5-守護進程(精靈進程)
---特殊的孤兒進程(脫離終端,脫離shell會話,運行在後臺)
6.進程優先級
- 1-什麼是進程優先級
---每個進程都有相應的優先級,以決定對CPU資源的分配調度
- 2-如何查看進程優先級
---使用 ps -l 查看PRI/NI進程的優先級, top-> r pid
UID : 代表執行者的身份
PID : 代表這個進程的代號
PPID :代表這個進程是由哪個進程發展衍生而來的,亦即父進程的代號
PRI :代表這個進程可被執行的優先級,其值越小越早被執行
NI :代表這個進程的nice值
---評判標準:根據NI的值:NI越小,優先級越高.[-20~19]總共41個評級,往高調整優先級需要root權限
修改NI的值: nice -n ni_val ./filename執行file文件並將NI設爲val
renice -n ni_val -p pid調整pid進程的NI值爲val
注意:NI的值不是進程的優先級,不過nice值可以影響到進程的優先級變化
---場景:磁盤密集型:調整優先級並沒有什麼明顯變化,沒有必要
CPU密集型:對CPU資源要求較高的,適用
- 3-爲什麼會有進程的優先級?
--- 進程具有各自的性質--批處理/交互式,不同進程完成不同的功能
--- 進程間具有競爭性,而cpu只有一個,爲了完成任務,多個進程會對cpu進行搶佔,因此,使用優先級解決競爭問題,保證每個進程都能被調度完成工作
---進程間具有獨立性,各個進程運行期間互不干擾
- 並行:多個進程在同一時刻都能運行在cpu上
- 併發:在一段時間段裏,只能有一個進程運行在cpu上,因爲時間太短以至於看起來像是同時運行在cpu上
7.環境變量
- 1-什麼是環境變量env?
---保存設置操作系統運行環境參數的變量
- 2-如何查看環境變量?
---通過指令echo $MYENV 打印變量內容到顯示終端
---env | grep MYENV 在系統變量中查詢MYENV
---set | grep MYENV 在普通變量中查詢MYENV
---main函數的第三個參數char* env[],可以通過getenv(const char* name);獲取環境變量值
- 3-如何定義環境變量?
---定義一個臨時變量:MYENV=1000 >>>注意:表達式不加空格!
---定義環境變量:export MYENV,用export設置的環境變量只屬於1個shell終端
---添加一個環境變量:PATH=$PATH+當前路徑,PATH爲默認路徑變量
- 4-如何移除環境變量?
----移除指定環境變量:unset MYENV
- 5-常見的環境變量
--- HOME、SHELL、PATH
- 6-環境變量的全局特性--繼承特性
---每一個shell終端都有自己獨立的環境變量,shell的子終端也具備其父終端的環境變量
---shell上執行的可執行程序繼承了該終端的環境變量,讓子程序執行命令,規避風險,峯值shell崩潰
- 7-shell原理
---將命令行的字符串解析成操作系統的庫命令--對系統調用接口的封裝
---程序替換:獲取字符串>>解析字符串>>fork()>>子進程進行程序替換
- 8-環境變量的設置位於/etc/profile文件
8.程序地址空間--代碼共享、數據獨有
- 1-什麼是虛擬地址空間?
虛擬地址空間---pcb中的mm_struct,是操作系統爲進程所描述的一段空間
struct mm_struct{
unsigned long size;
unsigned long code_start;
unsigned long code_end;
unsigned long data_start;
unsigned long data_end;
}
- 2-爲什麼要使用虛擬地址空間,而不直接給物理內存?
物理內存採用分頁式內存管理,實行碎片化管理;
虛擬地址空間採用頁式內存管理,通過虛擬頁號從頁表中的映射關係找到對應的物理頁號,根據頁表中的內存控制單元MMU獲取內存的訪問方式,最後根據頁內偏移得到實際地址,進行訪問
虛擬地址空間內,進程所佔用的連續內存段通過頁表映射關係映射到物理內存上,因爲物理內存的碎片化管理,可以充分利用物理內存,提高內存利用率。而如果實際訪問物理內存,給變量直接分配物理內存,可能會因爲缺乏訪問控制,而造成內存的非法訪問,導致程序崩潰。
虛擬地址空間 + 頁表 : a.提高內存利用率; b.對內存訪問進行控制
- 3-父子進程中打印同一個變量的值和地址,值不一樣,地址卻完全相同???
int val = 100;
pid_t pid = fork();
if (pid < 0) {
// 出錯
perror("fork error");
return -1;
} else if (pid == 0) {
//子進程
val = 50;
printf("%d: %d--%p\n", getpid(), val, &val);
} else {
//父進程
printf("%d: %d--%p", getpid(), val, &val);
}
共享:代碼通過虛擬地址空間,在頁表上映射到相同的物理內存
獨有:數據通過虛擬地址空間,在頁表上映射到不同的物理內存
---實際上相同的是虛擬地址空間裏的地址,而不是物理內存上的地址
寫時拷貝:爲了保證進程間的獨立性,在子進程的數據需要進行運算的時候,操作系統通過頁表的映射關係爲子進程的數據會在物理內存上重新開闢一段空間,然後更新頁表信息,然後將其拷貝返還給子進程。減少子進程的PCB複製開銷
父子進程具有各自的pcb,雖然子進程pcb是因爲複製父進程的pcb,它們的代碼映射到相同的物理內存,但是數據卻可能被映射到不同的物理內存上。這就是雖然父子進程的變量地址打印結果相同,值卻不同的原因。實現了父子進程之間代碼共享,數據獨有。
9.進程調度--進程的O(1)調度算法
- 1-優先級調度算法--結合先進先出
-----操作系統使用隊列管理pcb,採用先進先出算法進行調度進程。但是因爲進程具有優先級,每一次調度都需要遍歷這個隊列,查找最高的優先級然後對其調度,因此使用包含了140個隊列的隊列數組-----quene_array,每個元素分別對應140個優先級,同一個優先級內,按照先進先出算法調度。 這140個隊列就稱爲優先級隊列。
-----雖然使用隊列數組quene_array管理pcb,但每一次調度都需要根據優先級進行140個元素的遍歷訪問,所以操作系統使用一個二進制位圖來標識優先級隊列裏是否包含運行的隊列,當前隊列裏包含pcb,對應的二進制位圖就置1
-----爲了提高調度的效率,操作系統使用兩個隊列數組active_quene_array(需要調度的隊列),expired_quene_array(已經調度結束的隊列)進行調度pcb,從active中獲取就緒狀態的pcb,分配資源,調度結束後放置在expired中。
- 3-SJF-短作業優先調度算法
-----短作業優先(SJF)調度算法是從後備隊列中選擇一個或若干個估計運行時間最短的作業,將它們調入內存運行。而短進程優先(SPF)調度算法,則是從就緒隊列中選擇一個估計運行時間最短的進程,將處理機分配給它,使之立即執行,直到完成或發生某事件而阻塞時,才釋放處理機。
- 4-時間片輪轉調度算法
-----時間片輪轉調度算法主要適用於分時系統。在這種算法中,系統將所有就緒進程按到達時間的先後次序排成一個隊列,進程調度程序總是選擇就緒隊列中第一個進程執行,即先來先服務的原則,但僅能運行一個時間片,如100ms。在使用完一個時間片後,即使進程並未完成其運行,它也必須釋放出(被剝奪)處理機給下一個就緒的進程,而被剝奪的進程返回到就緒隊列的末尾重新排隊,等候再次運行。
----在時間片輪轉調度算法中,時間片的大小對系統性能的影響很大。如果時間片足夠大,以至於所有進程都能在一個時間片內執行完畢,則時間片輪轉調度算法就退化爲先來先服務調度算法。如果時間片很小,那麼處理機將在進程間過於頻繁切換,使處理機的開銷增大,而真正用於運行用戶進程的時間將減少。因此時間片的大小應選擇適當。
- 5-高響應比優先調度算法
----高響應比優先調度算法主要用於作業調度,該算法是對FCFS調度算法和SJF調度算法的一種綜合平衡,同時考慮每個作業的等待時間和估計的運行時間。在每次進行作業調度時,先計算後備作業隊列中每個作業的響應比,從中選出響應比最高的作業投入運行。
----響應比的變化規律可描述爲:
根據公式可知:
當作業的等待時間相同時,則要求服務時間越短,其響應比越高,有利於短作業。
當要求服務時間相同時,作業的響應比由其等待時間決定,等待時間越長,其響應比越高,因而它實現的是先來先服務。
對於長作業,作業的響應比可以隨等待時間的增加而提高,當其等待時間足夠長時,其響應比便可升到很高,從而也可
獲得處理機。克服了飢餓狀態,兼顧了長作業。