Linux pid与tgid概念

本文揭示了Linux中线程与进程的关系,指出线程是内核层面的进程特例,共享内存但不共享栈。重点讲解了如何通过task_struct中的tgid标识线程所属的进程组。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章来源:https://www.cnblogs.com/shihuvini/p/10043251.html

在Linux操作系统层面,线程其实只是特殊的进程,最特殊之处在于跟其他“线程进程“共享内存(包括代码段、数据段等,但不共享栈)。

熟悉Linux下C编程的同学都知道,每个进程都有自己的pid,每个线程都有自己的线程id(pthread_t类型),但这是在用户空间的层面。而在内核层面中,线程其实也是进程。为了更好地区分这些概念,我们用任务/task来指代内核中的进程概念,而依旧用进程来指定用户空间层面的进程。所以当我说task的时候,指的是内核层面,而当我说进程的时候,指的就是用户空间层面的。

回到刚才说的地方,每个线程都是一个task,所以每个线程都有自己的一份struct task_sruct,而且每个线程都有自己独特的pid。那内核通过什么来知道这个线程属于哪个进程呢?答案是task_sruct.tgid。是的,一个进程就是一个线程组,所以每个进程的所有线程都有着相同的tgid。

当程序开始运行时,只有一个主线程,这个主线程的tgid就等于pid。而当其他线程被创建的时候,就继承了主线程的tgid。这样,内核就可以通过tgid知道某个task属于哪个线程组,也就知道属于哪个进程了。当我们用ps命令或者getpid()等接口查询进程id时,内核返回给我们的也正是这个tgid。

所以什么是线程组?其实就是进程。

### LinuxPID 和 LWP 的概念及其关系 #### 1. **PID(Process ID)** 在 Linux 系统中,PID 是指进程标识符(Process Identifier)。它是内核用来唯一标识一个进程的数值。每个启动的新进程都会被分配一个唯一的 PID[^2]。无论是单线程还是多线程的应用程序,其主进程都有自己的 PID。 对于一个多线程的应用来说,主线程的 PID 就是整个线程组的 TGID(Thread Group ID),也就是线程组领导者的进程 ID[^1]。 --- #### 2. **LWP(Lightweight Process)** LWP 表示轻量级进程(Lightweight Process)。这是一个抽象的概念,用于区分线程和传统意义上的进程。在 Linux 内核实现中,线程本质上也是作为一个特殊的进程来处理的,所有的线程和进程都是作为 `task_struct` 实例存在于内核中的[^5]。 具体而言: - 每个线程对应一个 LWP。 - LWPs 受到内核统一调度和管理,就像普通的进程一样。 - TID(Thread ID 或 Task ID)是用来标识 LWP 的唯一编号[^3]。 因此,可以说 LWP 是一种更细粒度的任务单位,它允许多个线程共享同一地址空间的同时又能独立运行。 --- #### 3. **PID 和 LWP 的区别** | 属性 | PID | LWP | |--------------|---------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------| | 定义 | 进程标识符,代表一个完整的任务单元 | 轻量级进程,通常指的是线程 | | 地址空间 | 拥有自己的独立地址空间 | 同一进程中所有线程共享父进程的地址空间 | | 生命周期 | 主进程结束则子进程也可能随之终止 | 如果某个线程退出,其他线程不受影响 | | 唯一性 | 整个系统范围内唯一 | 在所属的线程组内唯一 | --- #### 4. **PID 和 LWP 的关系** - 当使用 `clone()` 系统调用创建一个新的线程时,该线程会被赋予一个独特的 TID(Task ID),这也是它的 LWP ID。 - 对于单线程进程,其 PID 和 LWP ID 是一致的。 - 对于多线程环境下的每一个线程,它们会有各自的 LWP ID(即 TID),但这些线程共享同一个 PID,这个 PID 实际上是指向线程组领导者(主线程)的 TGID[^1]。 换句话说,PID 更像是一个高层次上的标识,而 LWP 则深入到了具体的执行上下文中去定义了实际的工作单元。 --- ```c #include <iostream> #include <unistd.h> #include <pthread.h> #include <sys/types.h> #include <sys/syscall.h> using namespace std; // 获取当前线程的真实TID (LWP ID) pid_t gettid() { return static_cast<pid_t>(syscall(SYS_gettid)); } void* func(void* arg) { cout << "Thread ID (pthread): " << pthread_self() << endl; cout << "Process Group ID (TGID/PID): " << getpid() << endl; // 输出的是线程组ID cout << "Real Thread ID (LWP/TID): " << gettid() << endl; // 输出真实的线程ID cout << "----------------------------------------" << endl; sleep(5); } int main() { pthread_t tid[2]; pthread_create(&tid[0], nullptr, func, nullptr); sleep(2); // 让第一个线程先打印 pthread_create(&tid[1], nullptr, func, nullptr); pthread_join(tid[0], nullptr); pthread_join(tid[1], nullptr); return 0; } ``` 此代码片段展示了如何获取并对比不同类型的 ID: - `getpid()` 返回的是线程组 ID(TGID),也即是主线程的 PID。 - `gettid()` 提供真正的线程级别 ID(LWP/TID)。 - `pthread_self()` 给出了 POSIX 标准下线程的用户态表示形式。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值