進程結構
進程在內核的源代碼中以結構體表示,篇幅很長,在此列舉一小段關鍵代碼,可以發現是個雙向鏈表,具體的可以在內核目錄下找一個叫“sched.h”的頭文件。
struct task_struct { struct task_struct *real_parent; /* real parent process */ struct task_struct *parent; /* recipient of SIGCHLD, wait4() reports */ /* * children/sibling forms the list of my natural children */ struct list_head children; /* list of my children */ struct list_head sibling; /* linkage in my parent's children list */ struct task_struct *group_leader; /* threadgroup leader */ …… };
進程被存放在叫做任務鏈表(tasklist)的雙向循環鏈表中,linux通過slab分配器分配task_struct結構,這樣能達到對象復用和緩存着色(cache coloring)的目的。
結構體中主要由四部分組成
1.進程控制塊:進程標志
2.進程程序塊:可與其他程序共享
3.進程數據塊:進程專屬空間,用於存放各種私有數據以及堆棧空間
4.獨立的空間:線程
進程狀態
#define TASK_RUNNING 0 #define TASK_INTERRUPTIBLE 1 #define TASK_UNINTERRUPTIBLE 2 #define __TASK_STOPPED 4 #define __TASK_TRACED 8 /* in tsk->exit_state */ #define EXIT_ZOMBIE 16 #define EXIT_DEAD 32 /* in tsk->state again */ #define TASK_DEAD 64 #define TASK_WAKEKILL 128 #define TASK_WAKING 256
進程的狀態一共有五種。
進程的創建
在linux系統中,所有進程都是PID為1的init進程的后代。內核在系統啟動的最后階段啟動init進程。該進程讀取系統的初始化腳本,並執行其他的相關程序,最終完成系統啟動的整個進程。
進程是系統中基本的執行單位(線程是最小的調度單位),可以利用fork函數創建一個新的進程;
pid_t fork( void )
fork() 函數不需要參數,但返回兩次,返回值有三種情況:
(1)對於父進程,fork函數返回新的子進程的ID。
(2)對於子進程,fork函數返回0。
(3)如果出錯,fork函數返回-1。
fork函數創建一個新的進程,並從內核中為此進程得到一個新的可用進程ID,之后為這個新進程分配進程空間,並將父進程的進程空間中的內容復制到子進程的進程空間中,包括父進程的數據段+堆棧段,並與父進程共享代碼段。
fork函數之后,子進程從等待fork返回開始執行,而不是從頭開始。
注意:子進程完全復制了父進程的地址空間的內容,包括堆棧段+數據段的內容。但是,子進程並沒有復制代碼段,而是和父進程共享代碼段。代碼段是只讀的,不存在修改的問題,因此可以共用。在創建一個子進程后,子進程的地址空間完全和父進程分開,父子進程是兩個獨立的進程。
linux環境下提供一個和fork函數類似的函數,可以用來創建一個共用父進程地址空間的子進程。
pid_t vfork();
vfork()與fork()的區別:
(1)vfork產生的子進程和父進程完全共享地址空間,包括代碼段+數據段+堆棧段。子進程對共享資源進行的修改,也會影響到父進程。
(2)vfork函數產生的子進程一定比父進程先運行。即父進程調用了vfork函數后會等待子進程運行后再運行。



