深入理解 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进程 ...
随机推荐
- 编译执行 VS 解释执行
一般编译程序从对源程序执行途径的角度不同,可分为解释执行和编译执行. 所谓解释执行是借助于解释程序完成,即按源程序语句运行时的动态结构,直接逐句地边分析边翻译并执行.像自然语言翻译中的口译,随时进行翻 ...
- Java统计文件中字母个数
import java.text.DecimalFormat; import java.io.File; import java.io.FileReader; import java.io.Buffe ...
- JS高级面试题思路(装箱和拆箱、栈和堆、js中sort()方法、.js中Date对象中的getMounth() 需要注意的、开发中编码和解码使用场景有哪些)
1.装箱和拆箱: 装箱:把基本数据类型转化为对应的引用数据类型的操作: var num = 123 // num var objNum = new Num(123) // object console ...
- 集合转数组:toArray()最优化方法探索
优化背景 有些场景下(比如入参要求)需要将集合(比如List)转为数组类型,利用集合的toArray方法应该最为方便的,对于toArray()无参方法其返回的是Object[],强制转其他类型数组会C ...
- iPhone发布内测程序的方法
iPhone是封闭系统,不像android手机可以自行安装apk,所以iPhone手机发布内测程序相对来说复杂一些. 越狱安装 如果测试用户的机器已经越狱,那就简单了,直接打包成ipa,用户直接通过9 ...
- 『Python』matplotlib共享绘图区域坐标轴
1. 共享单一绘图区域的坐标轴 有时候,我们想将多张图形放在同一个绘图区域,不想在每个绘图区域只绘制一幅图形.这时候,就可以借助共享坐标轴的方法实现在一个绘图区域绘制多幅图形的目的. import n ...
- Winfrom 中完美设置webbrowser控件内核版本
前言 .NET 版本更新了一代又一代,winform中的webbrowser控件的IE内核版本却始终用的IE7,好多网站都对IE7已经不支持.webbrowser这个控件就显得有些鸡肋,经过查找大佬门 ...
- 基于深度学习的建筑能耗预测01——Anaconda3-4.4.0+Tensorflow1.7+Python3.6+Pycharm安装
基于深度学习的建筑能耗预测-2021WS-02W 一,安装python及其环境的设置 (写python代码前,在电脑上安装相关必备的软件的过程称为环境搭建) · 完全可以先安装anaconda(会自带 ...
- Spring Cloud Gateway 动态修改请求参数解决 # URL 编码错误传参问题
Spring Cloud Gateway 动态修改请求参数解决 # URL 编码错误传参问题 继实现动态修改请求 Body 以及重试带 Body 的请求之后,我们又遇到了一个小问题.最近很多接口,收到 ...
- eclipse下载安装
1.下载 网址:https://www.eclipse.org/downloads/ 找到:eclipse-inst-jre-win64.exe 下载... 2.安装 找到-->Eclipse ...