http://blog.csdn.net/rsyp2008/article/details/45150621

1 线程ID获取方法

Linux下获取线程有两种方法:

1)gettid或者类似gettid的方法

2)直接调用pthread_self()

gettid 获取的是内核中线程ID,而pthread_self 是posix描述的线程ID。

通过执行man手册,我们也能发现他们的区别:

SYNOPSIS
       #include <sys/types.h>
       pid_t gettid(void);
       Note: There is no glibc wrapper for this system call; see NOTES.
DESCRIPTION
       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).

对于单线程的进程,内核中tid==pid,对于多线程进程,他们有相同的pid,不同的tid。tid用于描述内核真实的pid和tid信息。

DESCRIPTION
       The  pthread_self()  function  returns  the ID of the calling thread.  This is the same value that is returned in *thread in the pthread_create(3) call that
       created this thread.
RETURN VALUE
       This function always succeeds, returning the calling thread's ID.

he thread ID returned by pthread_self() is not the same thing as the kernel thread ID returned by a call to gettid(2).

pthread_self返回的是posix定义的线程ID,man手册明确说明了和内核线程tid不同。它只是用来区分某个进程中不同的线程,当一个线程退出后,新创建的线程可以复用原来的id。

 

2  为什么需要两个ID描述线程?

通过执行如下代码, 我们也能发现他们的区别:

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <pthread.h>
  5. #include <sys/types.h>
  6. #include <sys/wait.h>
  7. //#include <sys/syscall.h>
  8. #define __NR_gettid 186
  9. void *f()
  10. {
  11. int status;
  12. printf("begin: pid: %d, tid:%ld, self: %ld\n", getpid(), (long int)syscall(__NR_gettid), pthread_self());
  13. int ret = fork();
  14. if(ret == 0){
  15. printf("[child] pid: %d, tid:%ld, self: %ld\n", getpid(), (long int)syscall(__NR_gettid), pthread_self());
  16. }else if(ret > 0){
  17. printf("[parent] pid: %d, tid:%ld, self: %ld\n", getpid(), (long int)syscall(__NR_gettid), pthread_self());
  18. waitpid(-1, &status, 0);
  19. }
  20. }
  21. int main()
  22. {
  23. int i = 0;
  24. pthread_t pth[1];
  25. while(i++<1){
  26. pthread_create(&pth[i], NULL, f, NULL);
  27. sleep(1);
  28. }
  29. pause();
  30. }

描述线程的id,为什么需要两个不同的ID呢?这是因为线程库实际上由两部分组成:内核的线程支持+用户态的库支持(glibc),linux在早期内核不支持线程的时候glibc就在库中(用户态)以纤程(就是用户态线程)的方式支持多线程了,POSIX thread只要求了用户编程的调用接口对内核接口没有要求。

linux上的线程实现就是在内核支持的基础上以POSIX thread的方式对外封装了接口,所以才会有两个ID的问题。

3 内部实现

glibc中并没有直接提供gettid函数,与之类似的方法是执行系统调用。

在头文件 /usr/include/x86_64-linux-gnu/asm/unistd_64.h 中找到__NR_gettid 的定义:

#define __NR_gettid 186

  1. gettid的包裹实现: syscall(__NR_gettid)

glibc中有如下调用:

  1. #define CHECK_TPP_PRIORITY(normal, boosted) \
  2. do                                \
  3. {                               \
  4. pid_t tid = syscall (__NR_gettid);            \
  5. \
  6. struct sched_param cep_sp;                \
  7. int cep_policy;                       \
  8. if (pthread_getschedparam (pthread_self (), &cep_policy,  \
  9. &cep_sp) != 0)         \
  10. {                           \
  11. puts ("getschedparam failed");            \
  12. ret = 1;                      \
  13. }                           \
  14. else if (cep_sp.sched_priority != (normal))       \
  15. {                           \
  16. printf ("unexpected priority %d != %d\n",     \
  17. cep_sp.sched_priority, (normal));     \
  18. }                           \
  19. if (syscall (__NR_sched_getparam, tid, &cep_sp) == 0  \
  20. && cep_sp.sched_priority != (boosted))        \
  21. {                           \
  22. printf ("unexpected boosted priority %d != %d\n", \
  23. cep_sp.sched_priority, (boosted));        \
  24. ret = 1;                      \
  25. }                           \
  26. }                               \
  27. while (0)

tid在内核中就是一个普通进程。

在glibc源码中,发现posix中pthread_self的实现如下:

  1. pthread_t
  2. __pthread_self (void)
  3. {
  4. return (pthread_t) THREAD_SELF;
  5. }
  6. strong_alias (__pthread_self, pthread_self)
  1. # define THREAD_SELF \
  2. ({ struct pthread *__self;                              \
  3. asm ("mov %%fs:%c1,%0" : "=r" (__self)                   \
  4. : "i" (offsetof (struct pthread, header.self)));            \
  5. __self;})
  1. struct pthread
  2. {
  3. union
  4. {
  5. #if !TLS_DTV_AT_TP
  6. /* This overlaps the TCB as used for TLS without threads (see tls.h).  */
  7. tcbhead_t header;
  8. #else
  9. struct
  10. {
  11. int multiple_threads;
  12. int gscope_flag;
  13. # ifndef __ASSUME_PRIVATE_FUTEX
  14. int private_futex;
  15. # endif
  16. } header;
  17. #endif
  1. typedef struct
  2. {
  3. void *tcb;        /* Pointer to the TCB.  Not necessarily the
  4. thread descriptor used by libpthread.  */
  5. dtv_t *dtv;
  6. void *self;       /* Pointer to the thread descriptor.  */
  7. int multiple_threads;
  8. int gscope_flag;
  9. uintptr_t sysinfo;
  10. uintptr_t stack_guard;
  11. uintptr_t pointer_guard;
  12. unsigned long int vgetcpu_cache[2];
  13. # ifndef __ASSUME_PRIVATE_FUTEX
  14. int private_futex;
  15. # else
  16. int __glibc_reserved1;
  17. # endif
  18. int rtld_must_xmm_save;
  19. /* Reservation of some values for the TM ABI.  */
  20. void *__private_tm[4];
  21. /* GCC split stack support.  */
  22. void *__private_ss;
  23. long int __glibc_reserved2;
  24. /* Have space for the post-AVX register size.  */
  25. __128bits rtld_savespace_sse[8][4] __attribute__ ((aligned (32)));
  26. void *__padding[8];
  27. } tcbhead_t;
  1. #define offsetof(Type, Member) ((size_t) &((Type *) NULL)->Member)

pthread_self 即是获取线程控制块tcb首地址 相对于进程数据的段的偏移, 注:pthread_create也是返回该值。

4 总结

gettid 获取的是内核中真实线程ID,  对于多线程进程来说,每个tid实际是不一样的。

而pthread_self获取的是相对于进程的线程控制块的首地址, 只是用来描述统一进程中的不同线程,

例子中,在线程中调用fork,只会将当前活动线程设置为活动(其他线程终止),且进程使用的都是虚拟地址,所以产生的pthread_self() 是相同的。

上述不匹配,对程序的实际运行,并没有影响,因为他们的tid是不同的。

本文中有关线程模型的基础知识,请参见:

http://www.ibm.com/developerworks/cn/linux/l-threading.html

gettid和pthread_self区别的更多相关文章

  1. gettid()和pthread_self()的区别

    Linux中,每个线程有一个tid,类型long,由sys_gettid()取得. Linux内核中并没有实现线程,而是由glibc线程库实现的POSIX线程.每个线程也有一个id,类型 pthrea ...

  2. gettid 和pthread_self的区别

    转: Linux中,每个进程有一个pid,类型pid_t,由getpid()取得.Linux下的POSIX线程也有一个id,类型 pthread_t,由pthread_self()取得,该id由线程库 ...

  3. getpid 与 gettid 与 pthread_self

    获取进程的PID(process ID) #include <unistd.h> pid_t getpid(void); 获取线程的TID(thread ID) 1)gettid或者类似g ...

  4. linux的pthread_self与gettid的返回值和开销的区别

    linux的pthread_self与gettid的返回值和开销的区别 linux的pthread_self与gettid的返回值和开销的区别 分类: 一些思考 2012-05-18 12:25 17 ...

  5. Linux下获取线程TID的方法——gettid()

    (转载)http://blog.csdn.net/delphiwcdj/article/details/8476547 如何获取进程的PID(process ID)? 可以使用: #include & ...

  6. c#与java的区别

    经常有人问这种问题,用了些时间java之后,发现这俩玩意除了一小部分壳子长的还有能稍微凑合上,基本上没什么相似之处,可以说也就是马甲层面上的相似吧,还是比较短的马甲... 一般C#多用于业务系统的开发 ...

  7. jquery和Js的区别和基础操作

    jqery的语法和js的语法一样,算是把js升级了一下,这两种语法可以一起使用,只不过是用jqery更加方便 一个页面想要使用jqery的话,先要引入一下jqery包,jqery包从网上下一个就可以, ...

  8. 【原】nodejs全局安装和本地安装的区别

    来微信支付有2年多了,从2年前的互联网模式转变为O2O模式,主要的场景是跟线下的商户去打交道,不像以往的互联网模式,有产品经理提需求,我们帮忙去解决问题. 转型后是这样的,团队成员更多需要去寻找业务的 ...

  9. 探究@property申明对象属性时copy与strong的区别

    一.问题来源 一直没有搞清楚NSString.NSArray.NSDictionary--属性描述关键字copy和strong的区别,看别人的项目中属性定义有的用copy,有的用strong.自己在开 ...

随机推荐

  1. ES6高级技巧(三)

    html转译 let c='<a href="#">Me & you</a>'.replace(/[&<>'"]/g, ...

  2. 【转帖】威盛x86 AI处理器架构、性能公布:媲美Intel 32核心

    威盛x86 AI处理器架构.性能公布:媲美Intel 32核心 https://www.cnbeta.com/articles/tech/920559.htm 除了Intel.AMD,宝岛台湾的威盛也 ...

  3. xshell怎么配置鼠标颜色

    在控制面板--> 鼠标属性 --> 指针 --> 文本选择 --> 浏览 --> beam_r.cur --> 打开 --> 应用 --> 确定

  4. Linux下查看.so和可执行文件是否debug编译

    如何判断一个.so是否是debug编译的? 如果用此方法:用file来查看一个.so, 根据是否包含”not stripped”来判断该.so是否是debug编译的.然而stripped/not st ...

  5. 9. Scala隐式转换和隐式值

    9.1 隐式转换 9.1.1 提出问题 先看一个案例演示,引出隐式转换的实际需要=>指定某些数据类型的相互转化 object boke_demo01 { def main(args: Array ...

  6. Kafka MirrorMaker 跨集群同步工具

    一.MirrorMaker介绍 MirrorMaker是Kafka附带的一个用于在Kafka集群之间制作镜像数据的工具.该工具从源集群中消费并生产到目标群集.这种镜像的常见用例是在另一个数据中心提供副 ...

  7. (原创)对比组态软件,使用C#开发的服务器和客户端软件的优势

    在当前经济形势和市场环境下,中小企业面对萧条的消费市场,恶化的外部贸易环境,刚性支出高成本人工和生产要素,通货膨胀,隐性的腐化支出等各种因素的作用导致企业生存艰难,企业需要在各方面削减支出,拓展市场寻 ...

  8. Ubuntu安装MySQL配置远程登录、utf8mb4字符集

    2019/11/19, Ubuntu Server 18.04,MySQL 5.7 摘要:Ubuntu Server 18.04 安装MySQL 5.7 并配置远程登录.utf8mb4字符集 由于My ...

  9. Spring Boot 的自动配置探究、自制一个starter pom

    //TODO @Conditional @Condition

  10. python基础流程控制

    流程控制主要分为三大类: 1.if 判断语句 2.while 循坏语句 3.for 循坏语句 下面以举例说明: if 判断语句: user1 = 'seven' user2 = 'alex' pass ...