深入理解 Linux的进程,线程,PID,LWP,TID,TGID
转载:https://www.linuxidc.com/Linux/2019-03/157819.htm
在Linux的top和ps命令中,默认看到最多的是pid (process ID),也许你也能看到lwp (thread ID)和tgid (thread group ID for the thread group leader)等等,而在Linux库函数和系统调用里也许你注意到了pthread id和tid等等。还有更多的ID,比如pgrp (process group ID), sid (session ID for the session leader)和 tpgid (tty process group ID for the process group leader)。概念太多可能很晕,但是只要对Linux的进程和线程的基本概念有准确的理解,这些ID的含义都迎刃而解。下面将介绍进程和线程的核心概念,并以一个示例程序来验证这些ID之间的关系。
Linux的进程和线程
Linux的进程和线程有很多异同点,可以Google下。但只要能清楚地理解一下几点,则足够理解Linux中各种ID的含义。
- 进程是资源分配的基本单位,线程是调度的基本单位
- 进程是资源的集合,这些资源包括内存地址空间,文件描述符等等,一个进程中的多个线程共享这些资源。
- CPU对任务进行调度时,可调度的基本单位 (dispatchable entity)是线程。如果一个进程中没有其他线程,可以理解成这个进程中只有一个主线程,这个主进程独享进程中的所有资源。
- 进程的个体间是完全独立的,而线程间是彼此依存,并且共享资源。多进程环境中,任何一个进程的终止,不会影响到其他非子进程。而多线程环境中,父线程终止,全部子线程被迫终止(没有了资源)。
上述第一点说明是最基础的,也是最重要的。
初步理解各种ID。基本上按照重要程度从高到低,在分割线下方的IDs不太重要。
- pid: 进程ID。
- lwp: 线程ID。在用户态的命令(比如ps)中常用的显示方式。
- tid: 线程ID,等于lwp。tid在系统提供的接口函数中更常用,比如syscall(SYS_gettid)和syscall(__NR_gettid)。
- tgid: 线程组ID,也就是线程组leader的进程ID,等于pid。
- ------分割线------
- pgid: 进程组ID,也就是进程组leader的进程ID。
- pthread id: pthread库提供的ID,生效范围不在系统级别,可以忽略。
- sid: session ID for the session leader。
- tpgid: tty process group ID for the process group leader。
从上面的列表看出,各种ID最后都归结到pid和lwp(tid)上。所以理解各种ID,最终归结为理解pid和lwp(tid)的联系和区别。
下面的图是一张描述父子进程,线程之间关系的图。

上图很好地描述了用户视角(user view)和内核视角(kernel view)看到线程的差别:
- 从用户视角出发,在pid 42中产生的tid 44线程,属于tgid(线程组leader的进程ID) 42。甚至用ps和top的默认参数,你都无法看到tid 44线程。
- 从内核视角出发,tid 42和tid 44是独立的调度单元,可以把他们视为"pid 42"和"pid 44"。
需要指出的是,有时候在Linux中进程和线程的区分也是不是十分严格的。即使线程和进程混用,pid和tid混用,根据上下文,还是可以清楚地区分对方想要表达的意思。上图中,从内核视角出发看到了pid 44,是从调度单元的角度出发,但是在top或ps命令中,你是绝对找不到一个pid为44的进程的,只能看到一个lwp(tid)为44的线程。
理解pid和lwp(tid)的示例程序
下面利用一个示例程序来进一步理解pid和lwp(tid),以及利用格式化的ps命令打印出各种ID。下面的程序在main函数中创建了2个子线程,加上main函数这个主线程,一共有3个线程。在3个线程中分别打印pthread id, pid和lwp(tid),来验证pid和lwp(tid)的关系。
1 #include <unistd.h>
2 #include <sys/syscall.h>
3 #include <stdio.h>
4 #include <pthread.h>
5 #define gettidv1() syscall(__NR_gettid) // new form
6 #define gettidv2() syscall(SYS_gettid) // traditional form
7 void *ThreadFunc1()
8 {
9 printf("the pthread_1 id is %ld\n", pthread_self());
10 printf("the thread_1's Pid is %d\n", getpid());
11 printf("The LWPID/tid of thread_1 is: %ld\n", (long int)gettidv1());
12 pause();
13 return 0;
14 }
15 void *ThreadFunc2()
16 {
17 printf("the pthread_2 id is %ld\n", pthread_self());
18 printf("the thread_2's Pid is %d\n", getpid());
19 printf("The LWPID/tid of thread_2 is: %ld\n", (long int)gettidv1());
20 pause();
21 return 0;
22 }
23 int main(int argc, char *argv[])
24 {
25 pid_t tid;
26 pthread_t pthread_id;
27 printf("the master thread's pthread id is %ld\n", pthread_self());
28 printf("the master thread's Pid is %d\n", getpid());
29 printf("The LWPID of master thread is: %ld\n", (long int)gettidv1());
30 // 创建2个线程
31 pthread_create(&pthread_id, NULL, ThreadFunc2, NULL);
32 pthread_create(&pthread_id, NULL, ThreadFunc1, NULL);
33 pause();
34 return 0;
35 }
注意编译的时候要利用-l指定library参数。
# gcc threadTest.c -o threadTest -l pthread
执行程序,结果如下:
# ./threadTest
the master thread's pthread id is 140154481125184
the master thread's Pid is 20992
The LWPID of master thread is: 20992
the pthread_1 id is 140154464352000
the thread_1's Pid is 20992
The LWPID/tid of thread_1 is: 20994
the pthread_2 id is 140154472744704
the thread_2's Pid is 20992
The LWPID/tid of thread_2 is: 20993
上述结果说明pthread id是pthread库提供的ID,在系统级别没有意义。pid都是线程组leader的进程ID,即20992。而lwp(tid)则是线程ID,分别是20993和20994。
同时利用ps来查看结果,注意ps默认只打印进程级别信息,需要用-L选项来查看线程基本信息。
# ps -eo pid,tid,lwp,tgid,pgrp,sid,tpgid,args -L | awk '{if(NR==1) print $0; if($8~/threadTest/) print $0}'
PID TID LWP TGID PGRP SID TPGID COMMAND
20992 20992 20992 20992 20992 30481 20992 ./threadTest
20992 20993 20993 20992 20992 30481 20992 ./threadTest
20992 20994 20994 20992 20992 30481 20992 ./threadTest
从上述结果中可以看到:
- PID=TGID: 20992
- TID=LWP: 20993 or 20994
- 至于SID,30481是bash shell的进程ID。
Linux用户态命令查看线程
top
默认top显示的是task数量,即进程。

可以利用敲"H",来切换成线程。如下,可以看到实际上有96个线程。也可以直接利用top -H命令来直接打印线程情况。

ps
ps的-L选项可以看到线程,通常能打印出LWP和NLWP相关信息。如下命令即可查看线程信息:
ps -eLf
pidstat
pidstat -t [-p pid号] 可以打印出线程之间的关系。
htop
要在htop中启用线程查看,开启htop,然后按<F2>来进入htop的设置菜单。选择“设置”栏下面的“显示选项”,然后开启“树状视图”和“显示自定义线程名”选项。按<F10>退出设置。
注:MAC的F2按fn+F2。
深入理解 Linux的进程,线程,PID,LWP,TID,TGID的更多相关文章
- Linux查看进程线程个数
1.根据进程号进行查询: # pstree -p 进程号 # top -Hp 进程号 2.根据进程名字进行查询: # pstree -p `ps -e | grep server | awk '{pr ...
- [转帖]Linux的进程线程及调度
Linux的进程线程及调度 本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10393707.html 本文为宋宝华<Linux的进程 ...
- linux根据进程号PID查找启动程序的全路径
linux根据进程号PID查找启动程序的全路径 2014-01-25 11:09 18629人阅读 评论(0) 收藏 举报 分类: Linux系统管理(29) 版权声明:本文为博主原创文章,未经博 ...
- 理解Linux的进程,线程,PID,LWP,TID,TGID
在Linux的top和ps命令中,默认看到最多的是pid (process ID),也许你也能看到lwp (thread ID)和tgid (thread group ID for the threa ...
- Linux的进程线程及调度
本文为宋宝华<Linux的进程.线程以及调度>学习笔记. 1 进程概念 1.1 进程与线程的定义 操作系统中的经典定义: 进程:资源分配单位. 线程:调度单位. 操作系统中用PCB(Pro ...
- 深入理解linux内核-进程和程序
进程描述符task_struct task_struct { //进程基本信息 pid 进程id号 tgid 线程组id号,与线程组领头线程pid号相同 getpid()返回该值 tasks in ...
- Linux下进程线程,Nignx与php-fpm的进程线程方式
1.进程与线程区别 进程是程序执行时的一个实例,即它是程序已经执行到课中程度的数据结构的汇集.从内核的观点看,进程的目的就是担当分配系统资源(CPU时间.内存等)的基本单位. 线程是进程的一个执行流, ...
- Linux下线程pid和tid
#include <stdio.h> #include <pthread.h> #include <sys/types.h> #include <sys/sy ...
- Linux的进程/线程间通信方式总结
Linux系统中的进程间通信方式主要以下几种: 同一主机上的进程通信方式 * UNIX进程间通信方式: 包括管道(PIPE), 有名管道(FIFO), 和信号(Signal) * System V进程 ...
随机推荐
- Vue个人博客关于标题自动打字机效果Typewriter
最近在写个人Blog 中间看过很多个人博客的开发 一大部分用的是Hexo框架或者vuePress框架 导入各种主题样式插件等等 但是看多了就会发现 很多博主的个人博客基本都很相似 并没有什么新东西呈现 ...
- [闻缺陷则喜]关于boost的想法
公司有个大约2万行的项目,用到了boost,我想取消掉不用boost.理由:一,可理解性差,除了高手很难弄懂.二,类太多,光头文件就1万多.大点的团队四五个高手,每人用一个boost类.高手流失后,很 ...
- 解读Flex布局及其基本使用
Flex布局的基本内容: felx布局意为"弹性布局",主要用于为盒状模型提供最大的灵活性.被广泛的应用于移动端,PC端的响应式布局. 首先:定义盒子为flex布局: .box{ ...
- TP5 windows中执行定时任务
1 首先先写个自定义命令文件 比如 Test 2 在网站根目录下建立文件 crond.bat ,内容:(把你在cmd上操作流程写一遍) D: cd workspace\wamp\tp5 D:\PHPW ...
- Nginx系列(7)- Nginx安装 | Linux
step-1 安装gcc 安装 nginx 需要先将官网下载的源码进行编译,编译依赖 gcc 环境,如果没有 gcc 环境,则需要安装: [root@localhost ~]# yum install ...
- Groovy系列(4)- Groovy集合操作
Groovy集合操作 Lists List 字面值 您可以按如下所示创建列表. 请注意,[]是空列表表达式 def list = [5, 6, 7, 8] assert list.get(2) == ...
- Django边学边记——中间件
特点 Django中的中间件是一个轻量级.底层的插件系统,可以介入Django的请求和响应处理过程,用于全局修改Django的输入或输出. 每个中间件组件负责做一些特定的功能.中间件全部注册在sett ...
- php--laravel --debug--mac
1>安装debug 一.下载xdebug文件 1.将phpinfo();的信息全部输入网址中的框,得到适配的xdebug版本: 网址:http://xdebug.org/wizard.php 2 ...
- Docker安装Jenkins 从GitLab上拉取代码打包SpringBoot项目并部署到服务器
1. 安装Jenkins 采用 Docker 方式安装 jenkins 首先,宿主机上需要安装java和maven,这里我的安装目录如下: 由于是docker安装,jenkins将来是在容器里面运行 ...
- 深入浅出WPF-01.WPF缘起
WPF缘起 自2012年起,根据公司需要,开始进入界面开发工作.公司是医疗器械行业,很多操作都是基于PC进行的,所以桌面应用开发尤为重要.原有项目都是基于MFC进行的开发,而且是VC6.0的技术,维护 ...