进程控制(1):进程标识符

    进程标识符(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程序设计大全,清华大学出版社

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。