1. 程式人生 > >程序建立方式以及對比

程序建立方式以及對比

一、程序概念

程序概念:程序就是正在執行的一個程式;(哲學)

正確理解程序概念:作業系統主要是一款搞管理的軟體,他通過驅動程式間接管理硬體,當然,他也會管理程序,既然是管理,那麼我們需要先描述,然後在組織。描述程序,程序資訊被放在一個程序控制塊的資料結構中,可以吧程序控制塊理解為程序屬性的集合,其實這個程序控制塊就是PCB,在Linux中就是task_struct。在這個阿結構體內部就是詳細對程序的一些描述,主要包括以下資訊:

1. 識別符號:要區分每一個程序,所以每一個都有唯一的一個程序id;

2. 輔助作業系統進行程序排程的屬性

(1)優先順序

(2)程式計數器(EPI):會記錄當前程式執行到哪;

(3)程序的狀態:包括執行狀態R、睡眠狀態S、殭屍狀態Z、磁碟休眠狀態D等

執行狀態R:也不一定在執行,可能是在執行佇列裡,因為cpu採取併發的方式進行排程程序(補充概念:併發:多個程序在一個cpu下采取程序切換的方式進行執行,因為cpu執行速率極快,所以可以視為同一時間內完成多個程序的排程。並行:多個程序在多個cpu下同時執行)

睡眠狀態S:也稱為可中斷睡眠,在等待某一程序結束;

殭屍狀態Z:殭屍狀態形成原因就是子程序結束了,可是父程序沒有對其做出相應的處理;

磁碟休眠狀態D:也稱為不可中斷睡眠,一般在等待I/O的結束

(4)上下文:把程序上次在cpu內部執行的現場儲存在暫存器內部;

(5)記賬資訊:包括處理器時間總和,使用的時鐘總和等;

3. I/O相關資訊:開啟檔案返回值檔案描述符;

二、程序建立方式及對比

         fork()會產生一個和父程序完全相同的子程序,但子程序在此後多會exec系統呼叫,出於效率考慮,linux中引入了“寫時複製“技術,也就是隻有程序空間的各段的內容要發生變化時,才會將父程序的內容複製一份給子程序。於是起初我就感到奇怪,子程序的物理空間沒有程式碼,怎麼去取指令執行exec系統呼叫呢?!原來在fork之後exec之前兩個程序用的是相同的物理空間(記憶體區),子程序的程式碼段、資料段、堆疊都是指向父程序的物理空間,也就是說,兩者的虛擬空間不同,但其對應的物理空間是同一個。當父子程序中有更改相應段的行為發生時,再為子程序相應的段分配物理空間,如果不是因為exec,核心會給子程序的資料段、堆疊段分配相應的物理空間(至此兩者有各自的程序空間,互不影響),而程式碼段繼續共享父程序的物理空間(兩者的程式碼完全相同)。而如果是因為exec,由於兩者執行的程式碼不同,子程序的程式碼段也會分配單獨的物理空間。在網上看到還有個細節問題就是,fork之後核心會通過將子程序放在佇列的前面,以讓子程序先執行,以免父程序執行導致寫時複製,而後子程序執行exec系統呼叫,因無意義的複製而造成效率的下降。

                           詳細情況可以看看這位仁兄的文章:十辨十析之辨一――fork()、寫時複製、vfork()

這三個方法是大佬L用 於建立子程序的三種方法。其實理解它們,要有一個實現上的意識即:程序->虛擬地址空間->實體地址空間即真實的儲存。使用者程序能感知的是程序的虛擬地址 空間,而虛擬地址空間->實體地址空間則由底層的核心來幫你實現。一個程序在地址空間上的表現形式就是:正文段,資料段,堆,棧。嗯,主要就是這四個部 分,核心為其分配相應的資料結構來表示它們,其看做是程序在地址空間的實體,也可以想象為靈魂。隨後核心會為這四部分分配相應的載體,即真正的物理儲存, 就像靈魂要附之於身體一樣,那麼,這些物理儲存就是程序的真正實體的,我們稱之為身體。那麼這三個方法有什麼不同呢?

ok,現在有一個父程序P1,這是一個主體,那麼它是有靈魂也就身體的哦。現在在其虛擬地址空間(有相應的資料結構表示)上有:正文段,資料段,堆,棧這四個部分,相應的,核心要為這四個部分分配各自的物理塊。即:正文段塊,資料段塊,堆塊,棧塊。至於如何分配,這是核心去做的事,在此不詳述。

1、fork*

現在P1用fork()函式為程序建立一個子程序P2,核心:(1)複製P1的正文段,資料段,堆,棧這四個部分,注意是其內容相同。(2)為這四個部分分配物理塊,P2的:正文段->PI的正文段的物理塊,其實就是不為P2分配正文段塊,讓P2的正文段指向P1的正文段塊,資料段->P2自己的資料段塊(為其分配對應的塊),堆->P2自己的堆塊,棧->P2自己的棧塊。

2、寫時複製

 寫時複製技術:核心只為新生成的子程序建立虛擬空間結構,它們來複制於父程序的虛擬究竟結構,但是不為這些段分配實體記憶體,它們共享父程序的物理空間,當父子程序中有更改相應段的行為發生時,再為子程序相應的段分配物理空間。

3、vfork

  vfork():這個做法更加火爆,核心連子程序的虛擬地址空間結構也不建立了,直接共享了父程序的虛擬空間,當然了,這種做法就順水推舟的共享了父程序的物理空間。

        通過以上的分析,相信大家對程序有個深入的認識,它是怎麼一層層體現出自己來的,程序是一個主體,那麼它就有靈魂與身體,系統必須為實現它建立相應的實體, 靈魂實體與物理實體。這兩者在系統中都有相應的資料結構表示,物理實體更是體現了它的物理意義。呵呵,說了這麼多,其實系統之所以提供這三個方法,也都是 從實現效率上來考慮的,一般fork後要exec,所以很多父程序的資料對於子程序來說都是不需要的,後兩種方法就是大佬L區別於Unix的一個主要特徵,也可以說是其高明處之一吧,其建立程序特別的高效,怎麼高效,通過以上的比較與分析,相信大家也能明白個五六了吧。