关于Linux线程id衍生出的讨论

来源:互联网 发布:mac 怎么启动jenkins 编辑:程序博客网 时间:2024/06/06 18:29

1.  内核中线程的id

Linux 内核中实际没有实现真正意义上的线程,或者说Linux的内核中并没有为“线程”这个概念提供一个专用的结构进行维护,其实现方法和进程一样。Linux内核中的 task_struct 结构记录了每个调度单元的信息(线程是内核中最小的调度单元),这个结构体中包括 pid 和 tgid 两个域。pid 是每个执行单元的核内唯一标识,而 tgid,thread groupid,则是一个线程组的号,其实也是主线程的进程号。每个进程,或者每个线程,在内核内都有一个唯一的pid号,这是因为内核并没有专门表示线程的结构。主线程和子线程的tgid号都相同,即都是主线程的pid号。也就是说:对内一个进程内的所有线程(当然这里指的是内核里),它们的pid号各不相同(目的是为了能够区别开来进行调度),但是它们的tgid号是相同的,都是主线程(第一个线程)是pid号。

2.  各个库函数的返回值

pthread_self()这个函数返回的是线程标识号,它与内核内维护的各项调度单元的信息无关,是Linux为了满足posix的要求而提供的一个标识唯一线程的机制。(一般来说,它是一个很奇怪的数字)

getpid()返回的是本进程的进程号,相照于内核内的数据来说,是tgid。不管是主线程,还是子线程,返回的值都一样。

getppid()返回的是父进程的进程号,这个没有什么特别的。

syscall(SYS_gettid)系统调用返回的是内核中的pid值,即每个线程(或进程)唯一的。这个和pthread_self()是有区别的。

syscall(SYS_getpid)系统调用返回的是内核中的tgid,与getpid()一样。

syscall(SYS_getppid)系统调用和getppid()一样。

3.  线程和进程在clone系统调用上的区别

无论是进程还是线程在用户空间创建的时候都调用clone系统调用,区别只在于它们提供的参数(选项)不同。

在Glibc源码中,pthread_create()函数在使用clone系统调用时,传入的选项参数如下:

#defineCLONE_SIGNAL          (CLONE_SIGHAND | CLONE_THREAD)

intclone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL

               | CLONE_SETTLS | CLONE_PARENT_SETTID

               | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM

               | 0);

      这些选项的意义可以通过查看帮助文档得到,这里要着重说一下CLONE_THREAD标志。使用CLONE_THREAD标志的结果,是告诉内核这个新创建的线程使用与父进程一样的tgid。这就导致了第一部分说的内核中线程的pid和tgid的区别。

      当然,在第一部分也说了,创建线程的创建进程的区别,就是在clone系统调用时,传递给它的这个“clone_flags”不同,具体的区别,可以看源码。这些标志的区别,也正是进程和线程的区别(不共享地址空间等)。

 

 

原创粉丝点击