线程种的gettid和pthread_self区别

| 2013年4月22日

这几天写程序老是使用thread来做,所以自己封装了一个threadbase的类来做简单的测试使用,但是在写的过程种发现又两个获取线程id的函数:pthread_self和gettid,那这两个函数有什么区别呢?

看gettid的man,这样写道:

gettid() returns the caller’s thread ID (TID). In a single-threaded process, the thread ID is equal to the process ID (PID, as returned by getpid(2)). In a multithreaded process, all threads have the same PID, but each one has a unique TID. For further details, see the discussion of CLONE_THREAD in clone(2).

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)).

而pthread_self的man这样写:

Thread IDs are only guaranteed to be unique within a process. A thread ID may be reused after a terminated thread has

been joined, or a detached thread has terminated.

The thread ID returned by pthread_self() is not the same thing as the kernel thread ID returned by a call to get‐ tid(2).

现在可以大体知道pthread_self是为了区分同一进程种不同的线程,而gettid获取的线程id和pid是有关系的。

写个程序检测一下:

void ThreadTest::Entry()
{
while (IsRun())
{
printf("ThreadTest is runing...pid:%d---ttid:%ld---self:0x%x\r\n",
getpid(), syscall(SYS_gettid), pthread_self());
Sleep(1000);
};
}

int main(int argc, char* argv[])
{
int num = 3;
ThreadTest testhread[num];
for (int i = 0; i < num; i++)
testhread[i].Start();

while (1)
{
printf("main loop ...... pid:%d---ttid:%ld---self:0x%x\r\n",
getpid(), syscall(SYS_gettid), pthread_self());
sleep(10);
};
}

输出:

main loop ...... pid:2822---ttid:2822---self:0xb7439b50

ThreadTest is runing...pid:2822---ttid:2824---self:0xb6c36b70
ThreadTest is runing...pid:2822---ttid:2825---self:0xb6435b70
ThreadTest is runing...pid:2822---ttid:2823---self:0xb7437b70

ps的结果

ps -eLf |grep threadtest|grep -v grep

UID PID PPID LWP C NLWP STIME TTY TIME CMD

helight 2822 4315 2822 0 4 17:32 pts/0 00:00:00 ./threadtest
helight 2822 4315 2823 0 4 17:32 pts/0 00:00:00 ./threadtest
helight 2822 4315 2824 0 4 17:32 pts/0 00:00:00 ./threadtest
helight 2822 4315 2825 0 4 17:32 pts/0 00:00:00 ./threadtest

运行两个进程

helight@zhwen:/data/code/xcode/xlib/thread$ ps -eLf |grep threadtest|grep -v grep
helight 2838 4315 2838 0 4 17:35 pts/0 00:00:00 ./threadtest
helight 2838 4315 2839 0 4 17:35 pts/0 00:00:00 ./threadtest
helight 2838 4315 2840 0 4 17:35 pts/0 00:00:00 ./threadtest
helight 2838 4315 2841 0 4 17:35 pts/0 00:00:00 ./threadtest
helight 2885 2842 2885 0 4 17:35 pts/5 00:00:00 ./threadtest
helight 2885 2842 2886 0 4 17:35 pts/5 00:00:00 ./threadtest
helight 2885 2842 2887 0 4 17:35 pts/5 00:00:00 ./threadtest
helight 2885 2842 2888 0 4 17:35 pts/5 00:00:00 ./threadtest

从这里看一看到这个gettid获取的线程id有可能就是进程id,也就是所说的主线程。

看代码:

pthread_self是在gblic中实现:

helight@zhwen:/data/kernel/glibc-2.17$ vim nptl/pthread_self.c

pthread_t
__pthread_self (void)
{
return (pthread_t) THREAD_SELF;
}

/* Return the thread descriptor for the current thread.

The contained asm must *not* be marked volatile since otherwise
assignments like
pthread_descr self = thread_self();
do not get optimized away. */
# define THREAD_SELF \
({ struct pthread *__self; \
asm ("movl %%gs:%c1,%0" : "=r" (__self) \
: "i" (offsetof (struct pthread, header.self))); \
__self;})

看到获取的就是这个pthread结构体中的header.self,

helight@zhwen:/data/kernel/glibc-2.17$ vim nptl/pthread_create.c

versioned_symbol (libpthread, __pthread_create_2_1, pthread_create, GLIBC_2_1);

struct pthread *pd = NULL;

.....

pd->header.self = pd;

可以看到这个获取的就是线程控制模块(tcb)的地址,也就是pthread_self的返回值。

再来看gettid的实现,这个是在内核中实现的,我下了2.6.32的内核来看

helight@zhwen:/data/kernel/linux-2.6.32$ vim kernel/timer.c

系统调用在这里

/* Thread ID - the internal kernel "pid" */
SYSCALL_DEFINE0(gettid)
{
return task_pid_vnr(current);
}

include/linux/sched.h

static inline pid_t task_pid_vnr(struct task_struct *tsk)
{
return __task_pid_nr_ns(tsk, PIDTYPE_PID, NULL);
}

 nr = pid_nr_ns(task->pids[type].pid, ns);

这里看到其实就是pid,所以linux中的线程在内核种都是task_struct的结构,也就是一个独立的调度单元。

看完本文有收获?请分享给更多人

关注「黑光技术」,关注大数据+微服务