Contents

Linux中PID,TID和PPID之间的差异

1. 简介

有不同的方式来引用 Linux 中执行的进程,因为每个进程都有不同的标识符,我们可以从中检索有关进程的信息。

在本教程中,我们将从它们的概念定义开始。接下来,我们将采用不同的方式从其他已知信息中检索标识符。我们将描述输出的含义以及标识符的相同或不同值意味着什么。

2. 背景资料

首先,让我们了解一些基本的并行计算术语。我们需要这些知识来理解我们稍后会看到的一些概念。

进程是为给定目的分配的一组资源,包括内存空间和文件描述符。

线程是调度程序处理的最简单的调度单元。换句话说,线程是处理器操作的最小指令集。

并行编程包括同时执行多个操作以实现更高性能的技术。两种常见的方式是多线程和多处理。选择取决于计算资源或软件架构等因素。

**多线程依赖于在同一进程内的多个线程中调度不同的任务。**这使得同一进程的线程共享系统分配的内存资源。

多处理 包括从一个父进程创建子进程

进程资源之间的通信 不像线程那样简单,需要显式声明。

3. 定义与区别

现在让我们看看每个标识符的定义。

3.1.PID(进程标识符)

它是一个唯一编号,用于标识内核中运行的每个进程。它从 1 开始,分配给systemd(或旧 Linux 发行版上的init )。

3.2. TID(线程标识符)

它是一个用于标识线程的整数

在串行编程中,TID 和 PID 是相同的,因为只有一个线程。

在多线程环境中,每个线程都有自己的 TID。来自同一进程的所有线程具有相同的 PID。

TID 始终等同于 LWP(LightWeight Process)。前者用于系统界面功能,而后者更多地用于用户端。

一个进程内的线程数就是NLWP,它代表Number of LWP。

3.3. PPID(父进程标识符)

当任何程序触发多处理序列时,都会有一个父进程,从中创建许多子进程。子进程的 PID 与父进程的 PID 不同。

但是,所有子进程都有相同的 PPID,它等于父进程的 PID,表示它们来自哪个父进程。

4. 从已知进程名中获取 PID

我们可以使用命令pidof 后跟进程的名称:

$ pidof firefox
19119 15535 15482 15182 15180 15040 14845 14751 14715 14666

输出列出了具有指定进程名称的所有 PID。

或者,有一个名为 pgrep 的工具 ,它提供了从应用程序名称中检索 PID 信息的高级功能。

要检索所有当前系统进程的 PID,top 之类的命令很有帮助。

5. 从已知 PID 获取所有 TID

一旦我们知道给定进程的 PID,我们就可以检索在 PID 下运行的所有线程的 TID。

有两种方法可以访问此信息。在 Linux 中,一切都是文件。在根目录中,有一个*名为*/proc/的目录,其中包含每个当前正在运行的进程的条目。在其中,还有另一个目录*task/,*它为进程中的每个线程都有一个目录。

让我们从上一个示例 (14715) 中获取一个 PID 来获取它的所有 TID:

$ ls /proc/14715/task
14715 14719 14720 14723 21345

输出显示在 PID 14715 下分组的所有 TID。

根据上一节对pidof的调用,我们可以看到 Firefox 是在多线程中运行的。对于第一个线程,PID 和 TID 始终匹配。TID将始终等于或大于 PID

检索相同信息的另一种方法是使用ps 命令。必须使用*–pid标志、-L标志(以获取 LWP 标识符)以及标志-O*后跟所需的输出列来为所需的 PID 调用该命令:

$ ps --pid 14715 -O tid,lwp,nlwp -L
    PID    TID     LWP  NLWP S TTY          TIME  COMMAND
  14715  14715   14715     5 S   ?      00:00:00  /usr/lib/firefox/firefox
  14715  14719   14719     5 S   ?      00:00:00  /usr/lib/firefox/firefox
  14715  14720   14720     5 S   ?      00:00:00  /usr/lib/firefox/firefox
  14715  14723   14723     5 S   ?      00:00:00  /usr/lib/firefox/firefox
  14715  21345   21345     5 S   ?      00:00:00  /usr/lib/firefox/firefox

除了之前检索到的相同 TID 之外,在 NLWP 列下获得了进程线程的总数。输出还显示 TID 和 LWP 相同。

6. 从已知 TID 获取 PID

另一个常见的查询是从已知的 TID 中检索 PID。为此,有两种方法依赖于与以前相同的命令。

通过使用**绝对目录 工具readlink 浏览 /proc目录,我们可以检索给定 TID 的 PID**。

对于 TID 14719,如下所示:

$ readlink -f /proc/*/task/14719 | cut -d/ -f3
14715

这里,管道中的cut 命令将readlink的输出(TID 的完整路径)拆分,并返回第三个斜杠之前的元素(即 PID)。

我们还可以使用ps结合awk 来检索相同的信息

我们可以像以前一样使用类似的标志(-L和*-O*),结合*-e*来返回所有内容:

$ ps -e -O tid -L | awk '$2 == 14719'
  14715  14719   S  ?   00:00:00   /usr/lib/firefox/firefox

在这里,我们将ps命令输出通过管道传输到awk,它会查找并返回第二列 ( $2 ) 等于我们正在搜索的 TID 的行。

7. 从已知 PID 获取 PPID

对于多处理,还有两种方法可以从 PID 中获取 PPID。

*在感兴趣的 PID的/proc/目录中,文件status*包含有关进程的信息。**搜索(使用grep 命令)PPid,我们可以得到 PID 进程的 PPID。

对于 PID 为 14715 的早期进程,PPID 为:

$ cat /proc/14715/status | grep PPid
PPid: 14666

我们应该注意,搜索词PPid的大写对于在status文件中找到正确的行很重要。

我们还可以通过在 ps 命令中使用 –pid 标志指定 PID 并请求PPID列作为输出(使用*-O ppid*标志)来检索 PPID:

$ ps --pid 14715 -O ppid
    PID   PPID   S  TTY       TIME   COMMAND
  14715  14666   S    ?   00:00:00   /usr/lib/firefox/firefox

8. 从已知的 PPID 获取所有 PID

最后,为了从 PPID 中获取 PID,我们只提出了一种解决方案,因为“目录”方法并不那么简单。

使用ps命令,我们可以通过使用标志-ppid*指定 PPID 来获取 PID*(标志*-O ppid*仅表示所有应该具有相同的 PPID):

$ ps --ppid 14666 -O ppid
    PID   PPID   S  TTY       TIME   COMMAND
  14715  14666   S    ?   00:00:00   /usr/lib/firefox/firefox
  14751  14666   S    ?   00:00:22   /usr/lib/firefox/firefox
  14845  14666   S    ?   00:04:59   /usr/lib/firefox/firefox
  15040  14666   S    ?   00:42:41   /usr/lib/firefox/firefox
  15180  14666   S    ?   00:08:20   /usr/lib/firefox/firefox
  15182  14666   S    ?   00:01:07   /usr/lib/firefox/firefox
  15482  14666   R    ?   00:15:37   /usr/lib/firefox/firefox
  15535  14666   S    ?   00:06:21   /usr/lib/firefox/firefox
  19119  14666   R    ?   00:01:27   /usr/lib/firefox/firefox

从结果来看,可以说firefox使用了多进程多线程。PID 为 14666 的进程会产生这些不同的进程。因此,这些进程(14715、14751、14845、…)的 PPID 为 14666。

从父进程创建的子进程的PID 大于 PPID。例如,PID 为 14666 的进程的 PPID 不能为 14666(正如我们在最后一个命令输出中看到的那样)。这是因为 PID 为 14666 的进程是firefox的父进程。鉴于系统产生了这个进程,它的 PPID 就是系统 PID。