
1. 馮諾依曼體系結構現代計算機的硬件基礎馮諾依曼體系結構是現代計算機的硬件體系結構它將計算機硬件劃分為五大類輸入設備如鍵盤、鼠標、掃描儀等輸出設備如顯示器、打印機、音響等存儲器內存主存和外部存儲器運算器執行算術和邏輯運算控制器協調和控制計算機各部件工作在計算機中數據流是圍繞內存工作的。這意味著CPU要處理任意數據都需要先把數據放到內存中。因此要運行一個程序先把這個程序的指令數據加載到內存中。2. 操作系統的功能層次劃分2.1 操作系統是什么操作系統是一個軟件負責對計算機上的軟硬件資源進行管理。2.2 系統調用接口操作系統內核提供給上層用于進行計算機操作的接口。2.3 庫函數庫函數是對系統調用接口進行的二次封裝接口如write、printf等。庫函數與系統調用接口的關系庫函數內部調用了系統調用接口。3. 進程概念3.1 不同角度的進程定義站在用戶的角度進程就是運行中的程序站在系統的角度進程就是對于程序的動態運行中描述這個描述在Linux下是一個結構體struct task_struct{ }3.2 進程描述了什么信息進程控制塊PCB中包含了豐富的信息標識符進程IDpid進程調度信息描述了如何調度一個程序的運行進程狀態對進程不同運行狀態進行描述讓進程在合適的時候做合適的事情進程的內存管理進程內部所有數據都會占據內存了解進程內部內存管理方式內存內打開的文件信息通過了解這塊信息更加深入地了解系統調用I/O進程間通信資源管理學習進程間通信進程信號信息描述進程的軟中斷相關內容4. 進程標識符與調度4.1 標識符進程ID進程ID其實就是一個數字。在Linux下可以通過ps指令查看進程信息ps -ef4.2 進程的調度并行多個進程可以同時運行串行有多個進程但是同一時間只能運行一個并行與串行在計算機上取決于CPU核心數量每個CPU核心上都有一套獨立的寄存器保存程序運行的上下文信息來執行指令。計算機上運行的程序非常多但是CPU核心很少如何讓它們同時運行CPU分時機制一個程序運行的時候只能在CPU上運行很短的一段時間時間片時間片運行完畢則切換下一個進程運行分時機制實現了多個程序在宏觀上的并行但我們要理解微觀上它們實際上是串行的一旦程序是切換運行的等切換回來的時候CPU又怎么知道該從哪里開始執行為了解決這個問題在struct task_structPCB-進程控制塊中就保存了一系列程序的運行上下文pc寄存器內容即將要執行的指令地址一系列上下文數據正在處理的數據即將要處理的數據......因此一旦CPU切換輪轉回來了就可以通過pid找到task_struct從其中取出這些上下文數據重新放到CPU寄存器中CPU就可以從原來的位置繼續向下執行處理原來沒有處理完的數據。5. 進程狀態5.1 三態模型就緒、運行、阻塞5.2 Linux下的進程狀態運行態就緒運行拿到時間片就能運行以及正在運行的都屬于運行態。可中斷休眠態可以被打斷的阻塞狀態阻塞態都有一個喚醒條件只有喚醒條件達成的時候才會轉為就緒態。不可中斷休眠態只能被條件喚醒不能被中斷打斷的阻塞狀態。停止態讓進程停止運行只能通過特定方式喚醒。追蹤態調試的時候涉及到的狀態。死亡態進程退出后資源全部釋放完畢處于的一個短暫的狀態。僵尸態一個進程退出后但是資源沒有完全被釋放的狀態。5.3 僵尸態詳解產生原因由于子進程退出但是父進程沒有關注子進程的退出狀態沒有等待也沒有忽略SIGCHLD信號所導致的。SIGCHLD信號就是子進程退出時操作系統給父進程發送的信號。忽略這個信號就是告訴操作系統子進程退出直接釋放資源我不管他的返回值。危害會造成系統資源泄露。解決kill -9強制殺死。避免進程等待wait/waitpid等待子進程退出獲取他的返回值。或者忽略SIGCHLD信號。6. 進程的內存管理程序地址空間6.1 程序地址空間概念程序地址空間進程的虛擬地址空間。進程的地址空間是虛擬的地址空間并不是給每個進程都分配了4G內存。程序地址空間實際上是系統給我們進程所描述的一個虛擬的地址空間并不是分配了這么多內存而是虛擬的地址分配。這個描述在pcb中是mm_struct結構體。6.2 虛擬地址空間作用實現數據在物理內存中的離散式存儲提高內存利用率并進行內存訪問控制提高進程獨立性。6.3 虛擬地址的實現虛擬地址的實現依賴了一個關鍵性技術頁表內存的分頁式管理。頁表信息虛擬地址和物理地址的映射關系訪問權限缺頁中斷標志......虛擬地址組成頁號針對頁面的編號 頁內偏移32位系統下地址大小4字節32個比特位頁號占據地址中的高20位頁內偏移占據地址中的低12位6.4 進程的獨立性每個進程操作系統都會為該進程創建task_struct(pcb)其中就包含虛擬地址空間描述和頁表信息。因此每個進程內部數據存儲所分配的地址都是虛擬地址。這也是為什么進程間通信需要操作系統提供進程間通信資源的原因——讓操作系統給多個不同的進程分一塊大家都能訪問的空間。6.5 內存置換當內存不夠用了操作系統如何處理內存置換操作系統認為內存中的很多數據并不是一直在訪問熱數據。因此當內存不夠用的時候操作系統就會根據一定的算法將指定內存中的數據置換出去存放到硬盤中。存放的這塊硬盤區域有個專業名稱交換分區。常見置換算法LRU最久未使用LFU最少未使用FIFO先進先出6.6 缺頁中斷當訪問內存數據的時候通過頁表將虛擬地址轉換為物理地址但是轉換的時候發現頁表中置位了缺頁中斷位當前這個虛擬地址對應的那塊內存數據沒有在內存中。缺頁中斷的處理從交換分區將數據重新置換到內存中更新頁表信息。6.7 分段式與段頁式內存管理分段式內存管理將代碼分為代碼段、數據段等對于程序的內存管理比較友好。段頁式內存管理對內存分段在每個段內進行分頁管理。7. 進程控制創建、退出、等待、程序替換7.1 創建pid_t fork()功能通過復制父進程的方式創建一個子進程。復制了什么緩沖區調度切換相關的上下文信息虛擬地址空間頁表信息文件描述符信息......pid_t pid fork(); if (pid 0) { // 錯誤處理 } else if (pid 0) { // 子進程運行的代碼 } else { // 父進程運行的代碼 }1. 復制了虛擬地址空間復制處理的子進程要執行的代碼、要處理的數據跟父進程是一樣的。創建子進程這里使用了寫時拷貝技術創建子進程后子進程與父進程指向同一塊內存區但是當任意一方對一塊內存區域數據進行修改則給當前進程重新開辟一塊空間拷貝新數據進去。這大大提高了創建子進程的效率。2. 復制了程序調度上下文信息pc寄存器保存的是即將要執行的指令地址程序運行到了哪里以及其他切換信息正在執行的指令正在處理的數據...7.2 退出終止程序的運行正常退出在main中return在任意位置調用exit()函數——exit()函數是一個庫函數在任意位置調用_exit()函數——_exit()函數是一個系統調用函數庫函數是對系統調用函數在特定場景下的一些功能補充庫函數內部調用了系統調用函數。庫函數在exit退出的時候會進行用戶態空間的一些資源清理操作例如緩沖區的數據刷新。異常退出程序在運行中的時候遇到了某種異常內存訪問錯誤導致程序崩潰。異常退出的情況下進程的返回值是沒有參考意義的。7.3 等待父進程創建子進程之后等待子進程退出為什么要等待捕獲子進程的退出狀態獲取他的返回值釋放子進程所有資源避免產生僵尸進程。pid_t wait(int *wstatus); pid_t waitpid(pid_t pid, int *wstatus, int options);wstatus內部包含兩個信息1. 進程的退出原因2. 進程的退出碼處理邏輯先取低7位判斷是否為0為0則表示正常退出status 0x7f再取低16位中的高8位當作退出碼進行處理(status 8) 0xff。7.4 程序替換默認創建子進程之后子進程與父進程的代碼段是一樣的可以通過fork返回值進行分支控制但是這樣會導致兩個不同的功能放在一個程序中實現代碼較為臃腫。如何讓子進程重新運行另一個程序呢使用程序替換將新的程序指令 數據加載到內存中。將子進程的頁表映射信息初始化并更新映射到新的內存區域加載到內存的新程序。初始化調度上下文信息讓當前進程pc寄存器指向新程序指令的起始位置。Exec函數族execl, execlp, execle, execv, execvp, execvel和v的差別設置程序運行參數的差別l是通過不定參逐個給予v是組織成數組一次性給予有沒有p的差別是否會到系統path環境變量指定的路徑下去找這個程序execl(/bin/ls) vs execlp(ls)有沒有e的差別子進程中是否自定義環境變量8. 內存內打開的文件信息8.1 進程的I/O文件的輸入輸出系統調用open, read, write, lseek, close文件描述符的本質是一個數組的下標一個進程內部能夠打開的文件數量是有上限的重定向就是修改描述符所對應的描述信息而實現的。重定向修改數據的輸出位置每個進程運行起來后默認會打開三個文件標準輸入-鍵盤描述符0標準輸出-顯示器描述符1錯誤輸出-顯示器描述符29. 進程間通信資源進程間通信就是讓操作系統為進程之間提供一個公共內存訪問區。原因進程之間具有獨立性。根據不同的應用場景操作系統提供了多種不同的方式管道數據傳輸、共享內存數據共享、消息隊列數據傳輸、信號量同步控制、套接字。9.1 管道1. 管道的本質內核中的一塊緩沖區匿名管道沒有名字的管道沒有標識符。其他進程怎么找到這個管道跟我通信呢特性只能用于具有親緣進程關系的進程間通信創建子進程子進程會復制父進程的信息。操作在創建子進程之前創建管道然后創建子進程子進程就復制進程內部打開的文件信息。int pipe(int fd[2]); // 接收兩個描述符 // fd[0]用于讀fd[1]用于寫命名管道有名字的管道可以被所有進程找到可以用于任意進程間通信。名字一個管道文件這個文件只是一個標識名字本質上管道就是內核的緩沖區。操作mkfifo(filename, flag);9.2 公共特性管道的特性是半雙工通信可以選擇方向的單向通信管道的數據寫滿了write就會阻塞管道中沒有數據read就阻塞管道所有讀端關閉則write就會觸發異常-SIGPIPE所有寫端關閉取完所有數據后繼續read不再阻塞而是返回0數據傳輸是字節流傳輸以字節為單位進行數據傳輸