馮諾依曼體系結構
馮諾依曼:計算機之父,在物理、化學、數學、也具有很大貢獻,開始是研究原子彈的。
馮諾依曼體系結構圖:
關於馮諾依曼,必須強調幾點:
- 這裏的記憶體指的是記憶體,且所有數據在記憶體中儲存的時候,採用2進位制的方式進行儲存;
- 不考慮快取情況,這裏的cpu能且只能對記憶體進行讀寫,不能存取外設(輸入或者輸出裝置);
- 外設要輸入或者輸出數據,也只能寫入記憶體或者從記憶體中讀取,且中央處理器的數據來源於記憶體。
- 一句話,所有裝置都只能直接和記憶體打交道。
概念
任何計算機系統都包含一個基本的程式集合,稱爲操作系統(OS)。籠統的理解,操作系統包括:內核(進程管理,記憶體管理,檔案管理,驅動管理);其他程式(例如函數庫,shell程式等等)。
操作系統本身就是一個軟體,管理計算機的軟硬體資源。原生的操作系統 = 操作系統內核 + 一組應用。
設計OS的目的
定位
在整個計算機軟硬體架構中,操作系統的定位是:一款純正的「搞管理」的軟體。如何理解管理?管理 = 描述 + 組織。
總結
計算機管理硬體:描述 + 組織。描述用struct結構體,組織用鏈表或其他高效的數據結構。
基本概念
操作系統是通過結構體來描述進程,通過雙向鏈表來組織進程。如下圖所示:
進程和程式的區別
程式:程式就是一個靜態的文字檔案,例如產生了一個靜態的out文字檔案。
進程:進程執行起來就是一個範例。從內核中分析在操作系統內核當中,爲進程建立了一個task_struct結構體;或稱之爲過程控制塊PCB(process control block),可以理解爲進程屬性的資訊。 task_struct是Linux內核的一種數據結構,它會被裝在到RAM記憶體中並且包含進程的資訊。可以理解爲,建立一個進程 ,就是建立了一個test_struct結構體, 也就是過程控制塊 。
struct task_struct
{
進程識別符號(PID):在當前的操作系統中唯一標識當前進程—進程識別符號相當於「身份證」
記憶體指針:指向程式的地址空間,如下圖所示:
進程當中的相關指令
進程狀態 :進程中分爲3種狀態
1. 執行狀態:可執行程式正在CPU上面進行運算;
2. 就緒狀態:程式已經準備好,在就緒佇列當中等待獲取CPU的資源;
3. 阻塞狀態:可執行程式有時候需要等待輸入裝置提供數據,等待IO就緒;
併發執行:多個進程使用一個CPU,每一個進程都獨佔CPU一小會,然後讓出CPU資源,供其他進程執行。
並行執行:多個進程,在同一時刻每一個進程都佔有一個CPU進程運算。
進程中狀態的表示規則
程式計數器:儲存進程即將要執行的下一條指令。
上下文數據:儲存上一次執行的時候,暫存器當中的值。
- 進程在執行的時候,進程會進行切換,切換是系統排程的;
- 在被切換出去的時候,該進程當中的程式計數器會儲存程式要執行的下一條指令,上下文資訊會儲存暫存器當中的值;
- 再次切換回來的時候,通過程式計數器和上下文資訊來恢復之前的場景,繼續運算。
IO資訊&記賬資訊
當前進程啓動的時間(15:39);當前程式佔據CPU的時間(0:00)
開啓檔案的資訊:ll /proc/ [PID]/fd
舉例:ll /proc/12341/ fd 開啓結果如下:其中0、1、2、代表標準輸入,標準輸出、標準錯誤。
進程優先順序(PR): - - 瞭解
PR值越小優先順序越低,反之優先順序越高。
PR(new) = PR(old) + NI;NI值時修正PR值得一個參數 。輸入r可進行修改, 輸入top可檢視系統資源消耗情況:
講解前提:
PCB(task_struct)中儲存有程式計數器和上下文資訊,用來執行和儲存命令,並且一塊PCB指向一塊程式的地址空間。
我們在建立子進程也就是新的進程中,需要呼叫fork函數。其命令如下:
#include <unistd.h>
peid_t fork(void);(peid_t是int型別)
其中fork函數是有返回值的,失敗返回值小於;成功返回兩次。父進程返回值大於0,子進程返回0。
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("-----begin-----\n");
fork();
printf("linux84 666\n");
return 0;
}
輸出結果:
執行邏輯:
在父進程中,先開始列印begin,然後父進程呼叫fork函數,子進程拷貝父進程PCB(task_struct),其中拷貝過去task_struct中的程式計數器儲存的是下一次進程即將要執行的命令,在本例也就是列印printf函數中的「linux84 666」,因此父進程和子進程會列印兩個「linux84 666」。
通過ps -ef可以檢視進程的pid和進程的父進程的pid,具體程式碼和例子看本篇部落格:父進程和子進程關係例題分析
在進程中還有和進程無關的知識點,但比較重要,想要閱讀的讀者可以參考這篇部落格:Linux中環境變數詳解
前提知識:父子進程,輸出地址是一致的,但是變數內容不一樣!能得出如下結論:
進程地址空間
所以之前說‘程式的地址空間’是不準 不準確的,準確的應該說成進程地址空間,那該如何理解呢?看圖:
說名:當fork完成之後,父進程之前的數據會被子進程通過頁表結構對映到同一塊實體記憶體上。
寫時拷貝:
前提內容:
進程虛擬地址空間分成了一頁一頁的小塊,實體記憶體分成了一塊一塊的小塊,一頁的大小 = 一塊的大小 = 4096k
頁表維護了頁和快的關係。
概念:
計算虛擬地址通過頁表對映到哪一個實體記憶體地址上。
注意: 上圖中的虛擬地址空間指的是一塊虛擬地址空間,虛擬地址空間由頁號和頁內偏移構成,頁號通過頁表上的頁號找到頁表中的快號,快號的起始地址加上頁內偏移找到實體記憶體上的地址。
計算規則:
虛擬地址的構成 = 短號 + 段內偏移