天天看點

linux 程序(一)---基本概念

一、程序的定義

        程序是作業系統的概念,每當我們執行一個程式時,對于作業系統來講就建立了一個程序,在這個過程中,伴随着資源的配置設定和釋放。可以認為程序是一個程式的一次執行過程。

二、程序與程式的差別

    程式時靜态的,它是一些儲存 在磁盤上得指令的有序集合,沒有任何執行的概念。

    程序是一個動态的概念,它是程式執行的過程,包括建立、排程和消亡。

三、linux系統中程序的表示

    在linux系統中,程序由一個叫task_struct的結構體描述,也就是說linux中的每個程序對應一個task_struct結構體。該結構體記錄了程序的一切。下面我們來看看它的核心字段。

struct task_struct

{

    //這個是程序的運作狀态,-1代表不可運作,0代表可運作,>0代表已經停止。

    volatile long state;

    /*

        flags是程序目前的狀态标志,具體如下:

        0x0000 0002表示程序正在被建立

        0x0000  0004表示程序正準備退出

        0x0000  0040表示此程序被fork出,但是并沒有執行exec

        0x0000   0400表示此程序由于其他程序發送相關信号而被殺死

    */

    unsigned int flags;

    //表示此程序的運作優先級

    unsigned     int   rt_priority;

    //該結構體記錄了程序記憶體使用的相關情況

    struct   mm_struct *mm;

    //程序号,是程序的唯一辨別

    pid_t   pid;

    //程序組号

    pid_t  tgid;

    //real_parent是該程序的"親生父親",不管其是否被"寄養"

    struct  task_struct  *real_parent;

    //parent是該程序現在的父程序,有可能是"繼父"

    struct   task_struct  *parent;

    //這裡children指的是該程序孩子的連結清單,可以得到所有孩子的程序描述符

    struct   list_head    children;

    //同理,sibling該程序兄弟的連結清單,也就是其父程序的所有孩子的連結清單

    struct    list_head    sibling;

    //這個是主線程的程序描述符,也許你會奇怪,為什麼線程用程序描叙符表示,因為linux并沒有單獨實作線程的相關結構體,隻用一            個程序來代替線程,然後對其做一些特殊的處理。

    struct   task_struct  *group_leader;

    //這個是該程序所有線程的連結清單

    struct   list_head   thread_group;

    //這個是該程序使用cpu時間的資訊,utime是在使用者态下執行的時間,stime 是在核心态下執行的時間

    cputime_t   utime,stime;

    //comm是儲存該程序名字的字元數組,長度最長為15,因為TASK_COMM_LEN為16

    char   comm[TASK_COMM_LEN];

    //打開的檔案相關資訊結構體

    struct  files_struct  *files;

    //信号相關資訊的句柄

    struct   signal_struct  *signal;

    struct   sigband_struct  *sighand;

};

    task_struct結構體非常龐大,我們沒必要去了解它的所有字段,隻需要對其中比較重要的字段加以關注就可以了。從上面的分析可以看出,一個程序至少有一下東東

1. 程序号(pid),就像我們的身份證ID一樣,每個人的都不一樣。程序ID也是,是其唯一标示。

2.程序的狀态,辨別程序是處于運作态,等待态,停止态,還是死亡态

A.運作态:此時程序 或者正在運作,或者準備運作

B.等待态:此時程序在等待一個事件發生或某種系統資源

C.停止态:此時程序被終止

D.死亡态:這是一個已終止的程序,但還在程序向量數組中,占有一個task_struct結構。

3.程序的優先級和時間片。不同有優先的程序,被排程運作的次序不一樣,一般是高優先級的程序先運作。時間片辨別一個程序将被處理器運作的時間

4.虛拟記憶體    大多數程序有一些虛拟記憶體(核心線程和守護程序沒有) ,并且Linux必須跟蹤記憶體如何映射到系統實體記憶體。

5.處理器相關上下文      一個程序可以被認為是系統目前狀态的總和。每當一個程序運作時,它要使用處理器的寄存器、棧等,這是程序的上下文(context)。并且,每當一個程序被暫停時,所有的CPU相關上下文必須儲存在該程序的task_struct中。當程序被排程器重新啟動時其上下文将從這裡恢複。

四、linux程序中的檔案

linux作業系統中每個程序有兩個資料結構描叙檔案相關資訊。

linux 程式(一)---基本概念

第一個:fs_struct,它包含此程序目前工作目錄和根目錄、umask。umask是新檔案被 建立的預設模式,它可以通過系統調用來改變。

第二個:files_struct,包含此程序正在使用的所有檔案的資訊。f_mode字段描述該檔案是以什麼模式建立的:隻讀、讀寫、還是隻寫。f_pos儲存檔案中下一個讀或寫将發生的位置。f_inode描叙檔案的VFS索引節點,而f_ops是一個例程向量的指針,每個代表一個想施加于檔案的操作的函數。

    每次一個檔案被打開時,files_struct中的空閑file指針之一就被用來指向新的file結構。Linux程序在啟動時有三個檔案描叙符被打開了,他們是标準輸入裝置、标準輸出裝置和标準錯誤裝置,并且通常是從建立此程序的父程序繼承得來的。所有對檔案的通路時通過傳遞或傳回檔案描叙符的标準系統調用進行的。這些描述符是程序fd向量的索引,是以标準輸入裝置、标準輸出裝置和标準錯誤裝置分别對應檔案描述符0、1和2。

五、程序中的虛拟記憶體

    在Linux作業系統中,當我們運作一個二級制可執行檔案時,作業系統将建立一個程序。此時如果将這個可執行二進制檔案的全部代碼和資料裝入實體記憶體将是浪費的。因為他們不可能同時使用。随着系統中程序數的增多,這種浪費将被成倍的擴大,系統将非常低效地運作。事實上,linux使用一種稱為請求調頁(demand-paging)的技術:隻有當程序要使用時其虛拟記憶體時,其對應的資料才裝入實體記憶體。是以,不是直接把代碼和資料裝入實體記憶體。linux核心隻修改程序的頁表,辨別虛拟記憶體頁存在但其對應的資料不在記憶體中。當程序想要通路代碼或資料時,系統硬體将産生頁故障并把控制交給Linux核心來解決。是以,對于程序位址空間中的每一個記憶體區,Linux都需要知道該虛拟記憶體來自何處,以及如何把它裝入記憶體以解決故障。

    當一個程序配置設定虛拟記憶體時,Linux并不真正為它保留實體記憶體。它隻是建立一個新vm_area_struct資料結構來描叙虛拟記憶體,這個結構被鍊入程序的虛拟記憶體清單。當程序試圖寫一個位于新配置設定虛拟記憶體區域的虛拟位址時,系統将産生頁故障。處理器試圖轉換該虛拟位址,但是因為沒有此記憶體的頁表項,它将放棄并産生一個頁故障異常,留給Linux核心來解決。Linux檢視被引用的虛拟位址是否是位于目前程序的虛拟記憶體位址空間。如果是Linux建立适當的PTE并為此程序配置設定一頁實體記憶體。代碼或資料可能需要從檔案系統或交換硬碟上讀入實體記憶體。然後程序可以從引起頁故障的那條指令處重新開機,并且因為這次記憶體實體位址存在,是以它可以繼續執行。如果不是,就是大家常常見到的"段錯誤"。

    呵呵,更纖細的介紹請看linux 程序位址空間的一步步探究。

from:http://blog.chinaunix.net/uid-26833883-id-3193588.html

繼續閱讀