Linux上的线程标识

POSIX threads库提供了pthread_self接口,可以获得进程里面的线程id,其类型为pthread_t类型。pthread_t不一定是一个数值类型,也有可能是一个结构体,它是一个非可移植性的类型,也就是说,在这个系统中,可能是unsigned int类型,在别的系统可能是long,double,或者甚至就是个结构体,都不得而知,所以非可移植。因此Pthreads专门提供了pthread_equal函数用于比较两个线程标识符是否相等。这就带来了一系列问题:

  1. 无法打印输出pthread_t,因为不知道其正真的类型。
  2. 无法比较pthread_t的大小或是hash值,所以不能作为关联容器的key
  3. pthread_t只是在进程内有意义,与操作系统的任务调度之间无法建立有效的关联。在/proc文件系统中找不到pthread_t对应的task。

因此,pthread_t并不适合作为程序中对线程的标识符。

在Linux上,可以使用gettid系统调用来获得线程的id,这么做的好处为:

  1. 他的类型为pid_t, 其值通常是一个小的整数型,便于在日志中输出
  2. 在现代的Linux操作系统中,她直接表示内核的任务调度id,因此在/proc文件系统中可以轻易找到其对应项
  3. 在其他的系统工具中容易定位到具体的线程。例如在top命令中,可以按照线程列出任务,可以根据CPU或是内存的使用率定位到具体的线程
  4. 任何时刻都是全局唯一的。
  5. 0为非法值,因为操作系统第一个进程init的pid为1。

如何获取线程的TID(thread ID)?

通过查看man得到如下描述:

(1) The gettid() system call first appeared on Linux in kernel 2.4.11.
(2) gettid() returns the thread ID of the current process. This is equal to the process ID (as returned by getpid(2)),
unless the process is part of a thread group (created by specifying the CLONE_THREAD flag to the clone(2) system call). All processes in the same thread group have the same PID, but each one has a unique TID.
(3) gettid() is Linux specific and should not be used in programs that are intended to be portable.
(如果考虑移植性,不应该使用此接口)

1
2
3
4
5
#include <sys/syscall.h>  
#define gettidv1() syscall(__NR_gettid)
#define gettidv2() syscall(SYS_gettid)
printf("The ID of this thread is: %ld\n", (long int)gettidv1());// 最新的方式
printf("The ID of this thread is: %ld\n", (long int)gettidv2());// 传统方式