進程標識符(PID)是一個進程的基本屬性,其作用類似於每個人的身份證號碼。根據進程標識符,用戶可以精確地定位一個進程。一個進程標識符唯一對應一個進程,而多個進程標識符可以對應同一個程序。本文將深入探討進程標識符及其相關操作。
1 進程標識符
每個進程在系統中都有唯一的一個ID標識它,這個ID就是進程標識符(PID)。因為其唯一,所以系統可以根據它准確定位到一個進程。進程標識符的類型為pid_t,其本質上是一個無符號整型的類型別名(typedef)。
接下來,我們來簡單介紹一個進程與程序的關系。所謂程序,不過是指可運行的二進制代碼文件,把這種文件加載到內存中運行就得到了一個進程。同一個程序文件可以被加載多次成為不同的進程。因此,進程與進程標識符之間是一對一的關系,而與程序文件之間是多對一的關系。
在Linux shell中,可以使用ps命令查看當前用戶所使用的進程。
xiaomanon@xiaomanon-machine:~$ ps -u xiaomanon PID TTY TIME CMD 1296 ? 00:00:00 init 1357 ? 00:00:00 sh 1359 ? 00:00:00 sleep 1362 ? 00:00:01 dbus-daemon 1371 ? 00:00:00 upstart-event-b 1375 ? 00:00:00 window-stack-br 1383 ? 00:00:00 gnome-keyring-d 1393 ? 00:00:00 upstart-file-br 1410 ? 00:00:00 bamfdaemon 1414 ? 00:00:00 upstart-dbus-br 1418 ? 00:00:00 upstart-dbus-br 1419 ? 00:00:00 ibus-daemon 1428 ? 00:00:00 gvfsd 1460 ? 00:00:00 unity-settings- 1482 ? 00:00:00 hud-service 1492 ? 00:00:00 at-spi-bus-laun 1495 ? 00:00:00 gvfsd-fuse 1497 ? 00:00:00 gnome-session 1498 ? 00:00:00 dbus-daemon 1506 ? 00:00:00 ibus-dconf 1507 ? 00:00:00 ibus-ui-gtk3 1510 ? 00:00:01 unity-panel-ser 1512 ? 00:00:00 ibus-x11 1523 ? 00:00:00 at-spi2-registr 1600 ? 00:00:00 indicator-messa 1605 ? 00:00:00 indicator-bluet 1610 ? 00:00:00 indicator-keybo 1615 ? 00:00:00 indicator-power 1625 ? 00:00:00 indicator-datet 1627 ? 00:00:00 indicator-sound 1630 ? 00:00:00 indicator-print 1635 ? 00:00:00 indicator-sessi 1653 ? 00:00:00 indicator-appli 1666 ? 00:00:00 evolution-sourc 1680 ? 00:00:00 pulseaudio 1733 ? 00:00:00 ibus-engine-sim 1793 ? 00:00:00 dconf-service 1795 ? 00:00:00 notify-osd 1860 ? 00:00:05 compiz 1901 ? 00:00:00 evolution-calen 1916 ? 00:00:00 unity-fallback- 1929 ? 00:00:00 nautilus 1933 ? 00:00:00 polkit-gnome-au 1937 ? 00:00:01 nm-applet 1945 ? 00:00:00 vmtoolsd 1998 ? 00:00:00 gvfs-udisks2-vo 2023 ? 00:00:00 gvfs-mtp-volume 2029 ? 00:00:00 gvfs-afc-volume 2033 ? 00:00:00 gconfd-2 2036 ? 00:00:00 gvfs-gphoto2-vo 2059 ? 00:00:00 gvfsd-trash 2078 ? 00:00:00 gvfsd-burn 2100 ? 00:00:00 gvfsd-metadata 2105 ? 00:00:00 telepathy-indic 2112 ? 00:00:00 mission-control 2118 ? 00:00:00 signon-ui 2126 ? 00:00:00 gnome-terminal 2132 ? 00:00:00 gnome-pty-helpe 2133 pts/1 00:00:00 bash 2182 ? 00:00:00 zeitgeist-datah 2187 ? 00:00:00 zeitgeist-daemo 2193 ? 00:00:00 zeitgeist-fts 2197 ? 00:00:00 cat 2207 pts/1 00:00:00 ps
第一列內容是進程標識符(PID),這個標識符是唯一的;最后一列內容是進程的程序文件名。我們可以從中間找到有多個進程對應同一個程序文件名的情況,這是因為有一些常用的程序被多次運行了,比如shell和vi編輯器等。
注意:如果ps命令不使用“-u 用戶名”作為參數,將不能檢查到后台運行的進程。
xiaomanon@xiaomanon-machine:~$ ps PID TTY TIME CMD 2133 pts/1 00:00:00 bash 2325 pts/1 00:00:00 ps
2 進程中重要的標識符
每個進程都有6個重要的ID值,分別是:進程ID、父進程ID、有效用戶ID、有效組ID、實際用戶ID和實際組ID。這6個ID保存在內核中的數據結構中,有些時候用戶程序需要得到這些ID。
例如,在/proc文件系統中,每一個進程都擁有一個子目錄,里面存有進程的信息。當使用進程讀取這些文件時,應該先得到當前進程的ID才能確定進入哪一個進程的相關子目錄。由於這些ID存儲在內核之中,因此,Linux提供一組專門的接口函數來訪問這些ID值。
Linux環境下分別使用getpid()和getppid()函數來得到進程ID和父進程ID,分別使用getuid()和geteuid()函數來得到進程的用戶ID和有效用戶ID,分別使用getgid()和getegid()來獲得進程的組ID和有效組ID,其函數原型如下:
#include <unistd.h> pid_t getpid(void); //獲取進程ID pid_t getppid(void); //獲取父進程ID uid_t getuid(void); //獲取用戶ID uid_t geteuid(void); //獲取有效用戶ID gid_t getgid(void); //獲取組ID gid_t getegid(void); //獲取有效組ID
以上6個函數,如果執行成功,則返回對應的ID值;失敗,則返回-1。除了進程ID和父進程ID這兩個值不能夠更改以外,其他的4個ID值在適當的條件下可以被更改。下面的示例程序用於獲取當前進程的6個ID值並打印出來。
//Get ID information about current process #include <stdio.h> #include <unistd.h> int main(void) { printf("PID: %u\n", getpid()); printf("PPID: %u\n", getppid()); printf("UID: %u\n", getuid()); printf("EUID: %u\n", geteuid()); printf("GID: %u\n", getgid()); printf("EGID: %u\n", getegid()); return 0; }
程序運行效果如下:
xiaomanon@xiaomanon-machine:~/Documents/c_code$ ./getid PID: 2681 PPID: 2133 UID: 1000 EUID: 1000 GID: 1000 EGID: 1000
3 參考文獻
[1] 吳岳,Linux C程序設計大全,清華大學出版社