尼古拉斯/Nicolas (上古卷軸主要人物)
程式和程序
什麼是程式?
- 程式就是一個被動的實體(需要被使用者指定執行),就是一個儲存在磁碟上的檔案包含了一系列的指令(被稱作可執行檔案)。
什麼事程序?
當可執行檔案被載入進記憶體後,程式就變成了程序。這個可執行檔案包含了指令,當載入進記憶體後,cpu就可以執行這些指令,直到所有指令執行完成。
程序是一個活動的實體,這個實體中包含了程式計數器用來指明下一條需要執行的指令
程式計數器(pc--programer counter):是一個cpu中的暫存器,裡面存放了下一條要執行指令的記憶體地址,通常,cpu取完一條指令之後會將PC暫存器的值加 "1",用來計算下一條要執行指令的地址。
當將一個程式程式碼載入進記憶體,並將第一條指令地址寫入pc暫存器之後,程序就建立完成了。
程序再記憶體中的分佈
當程序被載入進記憶體後,程式會將內分成幾塊區域----> 程式碼段、資料段,堆,棧
int global = 100; //全域性變數
void f(int x,int y){ //
int* p = malloc(100);
return;
}
void g(int a){ //
f(a,a+1);
return;
}
int main(){
static int i = 10; //靜態變數
g(i);
return 0;
}
-
以上程式碼編譯後會變成二進位制指令,這些指令會放在
text
區域,這個區域是隻讀區域。 -
這個程式碼的入口是
main
函式, 先將主函式的返回地址寫入棧,發現主函式中有staic 變數i和全域性變數global,則將這兩個變數存入data
-
呼叫g 函式,將a 放入stack 上,接著將g()函式的返回值(再main函式內地址,方便g函式返回的時候繼續執行main函式接下來的程式碼)也壓入棧
-
g函式會呼叫f函式,因此同理,將x,y,p 三個區域性變數放入棧中,接著將f的返回值放入棧中
-
p變數被動態分配了一塊記憶體,因此將p變數放入到heap上,同時分配100個位元組
-
f函式執行完返回:將f函式的返回地址讀取出來,由於函式要返回了,因此需要將f函式中的區域性變數地址清除,以及f的返回值也清除,接著執行g函式
-
g函式返回,取出g函式的返回地址,定位到main函式中的g(i)那段程式碼,同時清除g函式返回地址和g函式內部區域性變數
-
main函式返回,清空堆記憶體(由於沒有free p變數,p變數要等到函式退出才會銷燬)
併發的程序
併發與並行
再同一個時間發生或者存在的兩個或多個事件被稱為併發(concurrency)。
再同一個時間同時執行的兩個或多個事件被稱為並行(parallel)
當再單核機器上,同時建立多個程式,那就是併發,這兩個程式同時存在,但是再同一個時間只有一個程序再執行,如果在2核cpu上,執行兩個程序,兩個程序分別由不同的cpu來執行,那麼這種就叫做並行,因為他們再同一時間都在執行。
cpu上的併發
cpu再執行程式的時候會被劃分成一個個時間片,由作業系統來排程再這個時間片上由哪個程序來由cpu執行。當一個程序因為執行的時間到了而被另外一個程序頂替的佔有cpu,這個過程叫“程序切換”
其中實線代表的是程序佔有cpu,虛線代表的是程序沒有佔有cpu
程序狀態
根據上面併發的知識知道,程序並不是一直都在執行的,而且會由作業系統進行排程,有時執行,有時並沒有執行,因此需要給程序標記上他當前的狀態,好讓作業系統可以來排程管理程序。
三種基本狀態
程序總共有五種狀態,其中兩種是建立和終止,執行中的程序一般只在以下三個狀態切換
- 就緒態(ready):程序的程式碼再cpu上執行
- 執行態(running):程序具備執行條件,等待分配cpu
- 等待態(waiting):程序再等待某些時間的發生(比如IO操作結束或者一個訊號),不具備執行條件==
通過上面圖可以看出:
- running----> ready: 執行中的程序再遇到系統中斷(時鐘中斷患者io中斷等)的時候會被切換成就緒態或者有高優先順序的程序到達
- running----> waiting: 執行中的程序再遇到IO或者事件阻塞(比如將字串輸出到顯示器的時候,由於這些操作很慢,程序就會被切換成等待)
- ready-----> running: 當作業系統開始排程分配程序的時候,程序就有就緒態轉換為執行態
- waiting----->ready :當遇到IO或者某些事件完成