在 Linux 中有很多進程在同時運行,可以使用兩種方式對這些進程進行標識:
- 進程描述符的地址
- 進程標識符
對於當前操作系統中的每個獨立進程來說,其對應的進程描述符的地址以及進程標識符都是唯一的。
1. 進程描述符
爲了對進程進行管理,Linux 內核必須瞭解每個進程當前的執行狀態,這些狀態包括進程的優先級、進程的運行狀態、進程分配的地址空間等。因此,Linux 內核提供了一個 task_struct 類型的結構體進程描述符(process descriptor)來存放這些相關信息。
Linux 內核提供了一個數組 task 用於存放進程描述符,其包含指向系統中所有 task_struct 結構的指針。系統中的最大進程數目受 task 數組大小的限制,缺省值一般爲 512。
創建新進程時,Linux 將從系統內存中分配一個 task_struct 結構並將其加入 task 數組。當前運行進程的結構用 current 指針來指示。
以下是一個進程描述符的主要結構及其說明:
struct task struct
{
yolatile long state;
//進程的運行時狀態,-1代表不可運行,0代表可運行,>0代表已停止。
unsigned int flags;
//flags 是進程當前的狀態標識,具體說明如下:
//0x00000002 表示進程正在被創建
//0x00000004 表示進程正準備退出
//0x00000040 表示此進程被 fork 出,但是並沒有執行 exec
//0x00000400 表示此進程由於其他進程發送相關信號而被殺死
unsigned int rt_priority;
//進程的運行優先級
truct list_head tasks;
//list_head 結構體
struct mm_struct *mm;
//內存使用的相關情況
int exit_state;
int exit_code, exit_signal;
pid_t pid;
//進程標識號
pid_t tgid;
//進程組號
struct task_struct *real_parent;
//real_parent 是該進程的“親生父親”,不管其是否被 “寄養”
struct task_struct *parent;
//parent 是該進程現在的父進程,有可能是“繼父”
struct list_head children;
//children 指的是該進程孩子的鏈表,可以得到所有子進程的進程描述符
struct list_head sibling;
//sibling 是該進程兄弟的鏈表,也就是其父親的所有孩子的鏈表,用法與 children 相似
struct task_struct *group_leader;
//主線程的進程描述符
struct list_head thread_group;
//進程所有線程的鏈表
處理器 time_t utime, stime;
//進程相關時間
struct timespec start_time;
struct timespec real_ start_time;
//進程啓動時間
char comm[TASK_COMM_LEN];
//這個是該進程所有線程的鏈表
int link_count, total_link_count;
//文件系統信息計數
struct thread_struct thread;
//特定處理器下的狀態
struct fs_struct *fs;
//文件系統相關信息結構體
struct files_struct * files;
//打開的文件相關信息結構體
struct signal_struct *signal;
struct sighand_struct sighand;
//信號相關信息的句柄
unsigned long timer_slack_ns;
unsigned long default_timer_slack_ns;
//鬆弛時間值,用來規定 select() 和 poll() 的超時時間,單位是納秒
};
2. 進程標識符
進程標識符(Process ID)是進程描述符中最重要的組成部分,是在當前 Linux 系統中唯一的一個非負整數,用於標識和對應唯一的進程。
Linux 內核使用了一個數據類型 pid_t 來存放進程的進程標識符,這個數據類型的實質是一個32位的無符號整型數據。進程標識符被順序編號,通常來說是前一個進程的進程標識符的值加1。進程標識符可以重複使用,當一個進程被回收之後,過一段時間其標識符又可以被再次使用。Linux 內核上通常允許使用的進程標識符是 0~32767。
在Linux中,有幾個特殊的進程標識符所對應的進程。
- 進程標識符0:對應的是交換進程(swapper),用於執行多進程的調用。
- 進程標識符1:對應的是初始化進程(init),在自舉過程結束時由內核調用,對應的文件是/sbin/init,負責 Linux 的啓動工作,這個進程在系統運行過程中是不會終止的,可以說當前操作系統中的所有進程都是這個進程衍生而來的。
- 進程標識符2:可能對應頁守護進程(pagedaemon),用於虛擬存儲系統的分頁操作。
使用命令 ps -aux 可以查看系統中當前正在運行的進程的進程標識符以及其他一些信息。
可以使用 getpid 系列函數來獲得當前進程的進程標識符。
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void);
- getpid 函數用於獲得當前調用進程的進程標識符。
- getppid 用於獲得當前調用進程的父進程的進程標識符。
3. Linux進程的用戶
進程也有對應的實際用戶ID、實際組ID、有效用戶ID、有效組ID,對於這些用戶而言,每個進程同樣存在一個相應的標識符,Linux 提供了相應的函數用於獲取這些標識符。
#include <unistd.h>
#include <sys/types.h>
uid_t getuid(void);
uid_t geteuid(void);
gid_t getgid(void);
gid_t getegid(void);
-
getuid:返回進程的實際用戶標誌符。
-
geteuid:返回調用進程的有效用戶標識符。
-
getgid:返回調用進程的實際組標識符。
-
getegid:返回調用進程的有效組標識符。