转载: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. 1 #include <unistd.h>
  2. 2 #include <sys/syscall.h>
  3. 3 #include <stdio.h>
  4. 4 #include <pthread.h>
  5. 5 #define gettidv1() syscall(__NR_gettid) // new form
  6. 6 #define gettidv2() syscall(SYS_gettid) // traditional form
  7. 7 void *ThreadFunc1()
  8. 8 {
  9. 9 printf("the pthread_1 id is %ld\n", pthread_self());
  10. 10 printf("the thread_1's Pid is %d\n", getpid());
  11. 11 printf("The LWPID/tid of thread_1 is: %ld\n", (long int)gettidv1());
  12. 12 pause();
  13. 13 return 0;
  14. 14 }
  15. 15 void *ThreadFunc2()
  16. 16 {
  17. 17 printf("the pthread_2 id is %ld\n", pthread_self());
  18. 18 printf("the thread_2's Pid is %d\n", getpid());
  19. 19 printf("The LWPID/tid of thread_2 is: %ld\n", (long int)gettidv1());
  20. 20 pause();
  21. 21 return 0;
  22. 22 }
  23. 23 int main(int argc, char *argv[])
  24. 24 {
  25. 25 pid_t tid;
  26. 26 pthread_t pthread_id;
  27. 27 printf("the master thread's pthread id is %ld\n", pthread_self());
  28. 28 printf("the master thread's Pid is %d\n", getpid());
  29. 29 printf("The LWPID of master thread is: %ld\n", (long int)gettidv1());
  30. 30 // 创建2个线程
  31. 31 pthread_create(&pthread_id, NULL, ThreadFunc2, NULL);
  32. 32 pthread_create(&pthread_id, NULL, ThreadFunc1, NULL);
  33. 33 pause();
  34. 34 return 0;
  35. 35 }

注意编译的时候要利用-l指定library参数。

# gcc threadTest.c -o threadTest -l pthread

执行程序,结果如下:

  1. # ./threadTest
  2. the master thread's pthread id is 140154481125184
  3. the master thread's Pid is 20992
  4. The LWPID of master thread is: 20992
  5. the pthread_1 id is 140154464352000
  6. the thread_1's Pid is 20992
  7. The LWPID/tid of thread_1 is: 20994
  8. the pthread_2 id is 140154472744704
  9. the thread_2's Pid is 20992
  10. 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}'

  1. PID TID LWP TGID PGRP SID TPGID COMMAND
  2. 20992 20992 20992 20992 20992 30481 20992 ./threadTest
  3. 20992 20993 20993 20992 20992 30481 20992 ./threadTest
  4. 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相关信息。如下命令即可查看线程信息:

  1. ps -eLf

pidstat

pidstat -t [-p pid号] 可以打印出线程之间的关系。

htop

要在htop中启用线程查看,开启htop,然后按<F2>来进入htop的设置菜单。选择“设置”栏下面的“显示选项”,然后开启“树状视图”和“显示自定义线程名”选项。按<F10>退出设置。
注:MAC的F2按fn+F2。

深入理解 Linux的进程,线程,PID,LWP,TID,TGID的更多相关文章

  1. Linux查看进程线程个数

    1.根据进程号进行查询: # pstree -p 进程号 # top -Hp 进程号 2.根据进程名字进行查询: # pstree -p `ps -e | grep server | awk '{pr ...

  2. [转帖]Linux的进程线程及调度

    Linux的进程线程及调度 本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10393707.html 本文为宋宝华<Linux的进程 ...

  3. linux根据进程号PID查找启动程序的全路径

    linux根据进程号PID查找启动程序的全路径 2014-01-25 11:09 18629人阅读 评论(0) 收藏 举报  分类: Linux系统管理(29)  版权声明:本文为博主原创文章,未经博 ...

  4. 理解Linux的进程,线程,PID,LWP,TID,TGID

    在Linux的top和ps命令中,默认看到最多的是pid (process ID),也许你也能看到lwp (thread ID)和tgid (thread group ID for the threa ...

  5. Linux的进程线程及调度

    本文为宋宝华<Linux的进程.线程以及调度>学习笔记. 1 进程概念 1.1 进程与线程的定义 操作系统中的经典定义: 进程:资源分配单位. 线程:调度单位. 操作系统中用PCB(Pro ...

  6. 深入理解linux内核-进程和程序

    进程描述符task_struct task_struct { //进程基本信息 pid 进程id号 tgid 线程组id号,与线程组领头线程pid号相同   getpid()返回该值 tasks in ...

  7. Linux下进程线程,Nignx与php-fpm的进程线程方式

    1.进程与线程区别 进程是程序执行时的一个实例,即它是程序已经执行到课中程度的数据结构的汇集.从内核的观点看,进程的目的就是担当分配系统资源(CPU时间.内存等)的基本单位. 线程是进程的一个执行流, ...

  8. Linux下线程pid和tid

    #include <stdio.h> #include <pthread.h> #include <sys/types.h> #include <sys/sy ...

  9. Linux的进程/线程间通信方式总结

    Linux系统中的进程间通信方式主要以下几种: 同一主机上的进程通信方式 * UNIX进程间通信方式: 包括管道(PIPE), 有名管道(FIFO), 和信号(Signal) * System V进程 ...

随机推荐

  1. axios与vue-resource

    在Vue项目中前后端交互时,早期Vue使用Vue-resource实现异步请求.从Vue2.0之后就不再对vue-resource进行更新,Vue官方推荐使用axios. vue-resource V ...

  2. Android——菜单(Menu)

    菜单的运用在Android中很常见,今天就两节体育课,闲下来也想认真的学一学,正好项目中也会有应用.我是跟着菜鸟教程进行学习的,我相应的粘了一些我自己认为比较重要的,以供方便记录学习. 本章给大家带来 ...

  3. 【OI】蛇形填数题的深入探究

    题目:在 n×n 方阵里填入 1,2,...n×n, 要求蛇形填数.例如,n=4 时方阵为: 10  11  12  1 9    16  13  2 8    15  14  3 7     6  ...

  4. Shell系列(10)- bash环境变量(3)

    环境变量与用户自定义变量的区别 环境变量是全局变量,用户自定义变量是局部变量. 用户自定义变量只在当前的 shell 中生效,环境变量在当前 shell 和这个 shell 的所有子 shell 中生 ...

  5. appium日志

    2020-10-02 00:44:10:672 [Appium] Welcome to Appium v1.16.0 2020-10-02 00:44:10:673 [Appium] Non-defa ...

  6. JPA基本用法

    jpa基本查询 1.继承JpaRepository,生成了CRUD方法 public void testBaseQuery() throws Exception {   User user=new U ...

  7. 在 ASP.NET Core 中自动启用 CAP 事务

    本篇文章旨在描述如何在 ASP.NET Core项目中并以一种简便的方式启用CAP事务,因为在我们的示例中都是直接演示比较直观的方式,没有进行封装,有些初学者同学不太会,找到问我如何封装,本篇文章主要 ...

  8. Centos7 配置JDK 提示 /lib/ld-linux.so.2: bad ELF interpreter: No such file or direct

    解决办法:yum install glibc.i686

  9. Python简单爬取图书信息及入库

    课堂上老师布置了一个作业,如下图所示: 就是简单写一个借书系统. 大概想了一下流程,登录-->验证登录信息-->登录成功跳转借书界面-->可查看自己的借阅书籍以及数量... 登录可以 ...

  10. Multidimension Tools(多维工具)

    多维工具 # Process: 创建 NetCDF 栅格图层 arcpy.MakeNetCDFRasterLayer_md("", "", "&quo ...