Linux中,每个进程有一个pid,类型pid_t,由getpid()取得。Linux下的POSIX线程也有一个id,类型 pthread_t,由pthread_self()取得,该id由线程库维护,其id空间是各个进程独立的(即不同进程中的线程可能有相同的id)。Linux中的POSIX线程库实现的线程其实也是一个进程(LWP),只是该进程与主进程(启动线程的进程)共享一些资源而已,比如代码段,数据段等。
linux多线程环境下gettid() pthread_self() 两个函数都获得线程ID,可它们的返回值不一样。
linux使用进程模拟线程,gettid 函数返回实际的进程ID(内核中的线程的ID).
pthread_self 函数返回 pthread_create创建线程时的ID(POSIX thread
ID).
为什么有两个thread ID:
线程库实际上由两部分组成:内核的线程支持+用户态的库支持(glibc)。Linux在早期内核不支持线程的时候,glibc就在库中(用户态)以线程(就是用户态线程)的方式支持多线程了。POSIX thread只对用户编程的调用接口作了要求,而对内核接口没有要求。linux上的线程实现就是在内核支持的基础上,以POSIX
thread的方式对外封装了接口,所以才会有两个ID的问题。
在glibc中,pthread_self()返回的是THREAD_SELF,这是一个宏。其定义如下
# define THREAD_SELF
({ struct pthread *__self;
asm ("movl %%gs:%c1,%0" : "=r" (__self)
: "i" (offsetof (struct pthread, header.self)));
__self;})
这段代码返回了当前线程的descriptor(即struct pthread结构),pthread_self()得到的就是这个descriptor的地址,
也就是unsigned long int类型的pthread_t。知道了这一点就好办了,找到thread descriptor的定义:
struct pthread
{
...
pid_t tid;
...
}
接下来知道怎么做了吗?算好长度n,构造一个假的pthread结构。
struct pthread_fake
{
void *nothing[n];
pid_t tid;
};
用(struct pthread_fake *) pthread_self()->tid得到线程id了。
The man page for gettid says:
The thread ID returned by this call is not the same thing as a POSIX thread ID(i.e.,
the opaque value returned by pthread_self(3)).