摘自《Linux 环境编程:从应用到内核》

  在 Linux 中,目前的线程实现是 Native POSIX Thread Library,简称 NPTL。在这种实现下,线程又被称为轻量级进程(Light Weighted Process),每一个用户态的线程,在内核中都有一个调度实体,也拥有自己的进程描述符。

对于进程,可以使用下面的系统调用,获取进程 ID

  1. pid_t getpid(void);

如:

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <unistd.h>
  4.  
  5. int main()
  6. {
  7. pid_t pid = getpid();
  8. printf("pid = %d\n", pid);
  9. while();
  10. return ;
  11. }

打印:

  1. jingyg@jingyg:~/share/mytest/linux_userspace/$ gcc -g -Wall 0_1_hello_world.c -o hello_world
  2. jingyg@jingyg:~/share/mytest/linux_userspace/$ ./hello_world
  3. pid =

使用 ps 命令查看进程 ID,(加 -L 选项可以显示线程信息,LWP:线程 ID(调用 gettid()系统调用的返回值),NLWP:线程组内的线程个数)

  1. jingyg@jingyg:~$ ps -efL
  2. UID PID PPID LWP C NLWP STIME TTY TIME CMD
  3. jingyg : pts/ :: ./hello_world

可以看到 PID 和 LWP 的值一样。
多线程的进程,又被称作线程组,线程组内的第一个线程,在用户态被称作主线程(main thread)。内核在创建第一个线程时,会将线程组 ID (即进程 ID) 的值设置为第一个线程的线程 ID。

虽然 Linux 提供了 gettid 系统调用来返回线程 ID,但是可惜的是 glibc 并没有将该系统调用封装并开放给程序员使用。如果确实需要获取线程 ID,可以采用如下方法:

  1. #include <sys/syscall.h>
  2. int TID = syscall(SYS_gettid);

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <unistd.h>
  4. #include <sys/syscall.h>
  5.  
  6. int main()
  7. {
  8. pid_t pid = getpid();
  9. printf("pid = %d\n", pid);
  10.  
  11. int tid = syscall(SYS_gettid);
  12. printf("tid = %d\n", tid);
  13. return ;
  14. }

打印:

  1. jingyg@jingyg:~/share/mytest/linux_userspace/$ ./hello_world
  2. pid =
  3. tid =

pthread_self()

pthread 库中有一个 pthread_self() 接口用来获取线程 ID,但是这个 ID并不是内核中那个线程 ID

  1. #include <pthread.h>
  2. pthread_t pthread_self(void);

pthread_t 到底是个什么样的数据结构呢?因为 POSIX 标准并没有限制 pthread_t 的数据类型,所以该类型取决于具体实现。对于 Linux 目前使用的 NPTL 实现而言,pthread_t 类型的线程 ID,本质上就是一个进程地址空间上的一个地址,而且 pthread_t 类型的线程 ID很有可能被复用:

  1. #include <stdio.h>
  2. #include <pthread.h>
  3.  
  4. void* thread_work(void* param)
  5. {
  6. printf("pthread_self : %p\n", (void*)pthread_self());
  7. return NULL;
  8. }
  9.  
  10. int main()
  11. {
  12. pthread_t tid = ;
  13. int ret = pthread_create(&tid, NULL, thread_work, NULL);
  14. ret = pthread_join(tid, NULL);
  15.  
  16. ret = pthread_create(&tid, NULL, thread_work, NULL);
  17. ret = pthread_join(tid, NULL);
  18. return ;
  19. }

打印:(编译 pthread 相关接口时,需要加上 -lpthread 选项,如 gcc -g -Wall 0_1_hello_world.c -o hello_world -lpthread)

  1. jingyg@jingyg:~/share/mytest/linux_userspace/$ ./hello_world
  2. pthread_self : 0xb7525b40
  3. pthread_self : 0xb7525b40

如果线程退出了,重新创建的线程很可能复用同一个 pthread_t 类型的 ID。在设计调试日志时,用 pthread_t 类型的 ID 来标识进程就不太合适了。

采用 pid_t 类型的线程 ID 来唯一标识进程由以下优势:

  • 返回类型是 pid_t 类型,进程之间不会存在重复的线程 ID,而且不同线程之间也不会重复,在任意时刻都是全局唯一的值
  • proc 中记录了线程的相关信息,可以方便的查看 /proc/pid/task/tid 来获取线程对应的信息
  • ps 命令提供了查看线程信息的 -L 选项,可以通过输出中的 LWP 和 NLWP,来查看同一个线程组的线程个数和线程 ID 的信息

如:

  1. #include <stdio.h>
  2. #include <pthread.h>
  3. #include <sys/syscall.h>
  4.  
  5. void* thread_work(void* param)
  6. {
  7. int tid = syscall(SYS_gettid);
  8. printf("tid : %d\n", tid);
  9. sleep();
  10. return NULL;
  11. }
  12.  
  13. int main()
  14. {
  15. pthread_t tid1 = ;
  16. pthread_t tid2 = ;
  17. pthread_t tid3 = ;
  18. int ret = pthread_create(&tid1, NULL, thread_work, NULL);
  19. ret = pthread_create(&tid2, NULL, thread_work, NULL);
  20. ret = pthread_create(&tid3, NULL, thread_work, NULL);
  21.  
  22. ret = pthread_join(tid1, NULL);
  23. ret = pthread_join(tid2, NULL);
  24. ret = pthread_join(tid3, NULL);
  25. return ;
  26. }

ps 命令查看线程 ID:

  1. jingyg@jingyg:~$ ps -efL | grep hello_world
  2. jingyg : pts/ :: ./hello_world
  3. jingyg : pts/ :: ./hello_world
  4. jingyg : pts/ :: ./hello_world
  5. jingyg : pts/ :: ./hello_world

查看 proc:

  1. jingyg@jingyg:~$ ll /proc//task/
  2. total
  3. dr-xr-xr-x jingyg jingyg Jul : ./
  4. dr-xr-xr-x jingyg jingyg Jul : ../
  5. dr-xr-xr-x jingyg jingyg Jul : /
  6. dr-xr-xr-x jingyg jingyg Jul : /
  7. dr-xr-xr-x jingyg jingyg Jul : /
  8. dr-xr-xr-x jingyg jingyg Jul : /

线程 ID的更多相关文章

  1. linux查看某个进程的线程id(spid)

    鉴于linux下线程的广泛使用 我们怎么查看某个进程拥有的线程id了 现在很多服务的设计 主进程->子进程->线程(比如mysql,varnish) 主进程负责侦听网络上的连接 并把连接发 ...

  2. 得到某个进程所有线程ID和入口地址

    #include <windows.h> #include <tlhelp32.h> #include "iostream" using namespace ...

  3. 线程、线程句柄、线程ID

     什么是句柄:句柄是一种指向指针的指针.我们知道,所谓指针是一种内存地址.应用程序启动后,组成这个程序的各对象是住留在内存的.如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址 ...

  4. Android 开发 知晓各种id信息 获取线程ID、activityID、内核ID

    /** * Returns the identifier of this process's user. * 返回此进程的用户的标识符. */ Log.e(TAG, "Process.myU ...

  5. 7.线程id,优先级讲解

    1.线程id可以通过Thread对象的getId()方法得到,在线程出了问题,为什么CPU占用这么高的时候,查的时候我们可以在堆栈信息中找到对应线程,然后干掉该线程就好! 2.而线程对象的getNam ...

  6. linux获取线程ID

    pthread_self()获取当选线程的ID.这个ID与pthread_create的第一个参数返回的相同.但是与ps命令看到的不同,因此只能用于程序内部,用于对线程进行操作. #include & ...

  7. 利用进程ID获取主线程ID

    利用进程ID获取主线程ID,仅适用于单线程.多线程应区分哪个是主线程,区分方法待验证 (1)好像可以用StartTime最早的,不过通过线程执行时间不一定可靠,要是在最开始就CreateThread了 ...

  8. 线程、线程ID获取

    一.进程ID获取 1.1  当前进程的Id 方法1 通过进程名获取 下面的例子中,也包含了获取该进程下的线程的方法. System.Diagnostics.Process[] processes:bo ...

  9. java 获取当前进程id 线程id

    java  获取当前进程id  线程id RuntimeMXBean (Java Platform SE 8 ) https://docs.oracle.com/javase/8/docs/api/j ...

随机推荐

  1. $Django 路飞之课程下的分类,用户登陆成功前端存cookie,

    一 课程分类显示 宗旨:总的再次过滤 二 Cookie # export default new Vuex.Store({ state: { name:'', token:'', }, mutatio ...

  2. ios消息机制

    ios消息机制介绍 ios 调用每一个方法的时候其实是走的ios的消息机制 举例介绍一下 创建一个Pserson类 有一个eat 对象方法 那么下面的代码可以用消息机制实现  导入消息头文件    # ...

  3. nodejs之koa-router与koa-body搭配使用

    简介 koa需要搭配中间件来做接口更方便,使用Koa-body & Koa-router 使用 koa2 创建接口,处理post请求 const koa=require("koa&q ...

  4. Android 框架 Afinal使用

    介绍android Afinal框架功能: Afinal是一个开源的android的orm和ioc应用开发框架.在android应用开发中,通过Afinal的ioc框架,诸如UI绑定,事件绑定,通过注 ...

  5. 自己没有记住的一点小知识(ORM查询相关)

    一.多对多的正反向查询 class Class(models.Model): name = models.CharField(max_length=32,verbose_name="班级名& ...

  6. Python关于类的实操

    实操一:总结 1.什么是绑定到对象的方法,如何定义,如何调用,给谁用?有什么特性? 2.什么是绑定到类的方法,如何定义,如何调用,给谁用?有什么特性? 3.什么是解除绑定的函数,如何定义,如何调用,给 ...

  7. laravel 多对多关联 attach detach sync

    用户表和角色表,多对多关联,一个用户有多个角色,一个角色属于多个用户 添加多对多关联 attach: 给1号用户添加1号角色,并把关联表的column字段赋值为$value,后边的数组需要的时候再添加 ...

  8. WampServer & XAMPP Configure with MariaDB and MySQL

    第一部分补上次的一个问题 1.WampServer 3不支持的硬件格式 FAT3和 exFAT 他只能工作在NTFS的格式硬盘上. 不能在Windows XP上运行. 安装 WampServer 必须 ...

  9. 广工赛-hdu6469-树链压缩/二分

    比较复杂的一题.. 不管是二分答案还是直接做,都需要压缩树链 /* 给定n种怪物,每个怪物有属性a[i] 打死第i种怪物后,第i只怪物会分裂成a[i]个第i-1种怪 如果打死的是第1种,那么获得经验a ...

  10. bzoj2200拓扑排序+最短路+联通块

    自己写的不知道哪里wa了,明明和网上的代码差不多.,. /* 给定一张图,有的边是无向边,有的是有向边,有向边不会出现在环中,且有可能是负权值 现在给定起点s,求出s到其余所有点的最短路长度 任何存在 ...