gettid和pthread_self区别
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描述线程?
通过执行如下代码, 我们也能发现他们的区别:
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <pthread.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- //#include <sys/syscall.h>
- #define __NR_gettid 186
- void *f()
- {
- int status;
- printf("begin: pid: %d, tid:%ld, self: %ld\n", getpid(), (long int)syscall(__NR_gettid), pthread_self());
- int ret = fork();
- if(ret == 0){
- printf("[child] pid: %d, tid:%ld, self: %ld\n", getpid(), (long int)syscall(__NR_gettid), pthread_self());
- }else if(ret > 0){
- printf("[parent] pid: %d, tid:%ld, self: %ld\n", getpid(), (long int)syscall(__NR_gettid), pthread_self());
- waitpid(-1, &status, 0);
- }
- }
- int main()
- {
- int i = 0;
- pthread_t pth[1];
- while(i++<1){
- pthread_create(&pth[i], NULL, f, NULL);
- sleep(1);
- }
- pause();
- }
描述线程的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
- gettid的包裹实现: syscall(__NR_gettid)
glibc中有如下调用:
- #define CHECK_TPP_PRIORITY(normal, boosted) \
- do \
- { \
- pid_t tid = syscall (__NR_gettid); \
- \
- struct sched_param cep_sp; \
- int cep_policy; \
- if (pthread_getschedparam (pthread_self (), &cep_policy, \
- &cep_sp) != 0) \
- { \
- puts ("getschedparam failed"); \
- ret = 1; \
- } \
- else if (cep_sp.sched_priority != (normal)) \
- { \
- printf ("unexpected priority %d != %d\n", \
- cep_sp.sched_priority, (normal)); \
- } \
- if (syscall (__NR_sched_getparam, tid, &cep_sp) == 0 \
- && cep_sp.sched_priority != (boosted)) \
- { \
- printf ("unexpected boosted priority %d != %d\n", \
- cep_sp.sched_priority, (boosted)); \
- ret = 1; \
- } \
- } \
- while (0)
tid在内核中就是一个普通进程。
在glibc源码中,发现posix中pthread_self的实现如下:
- pthread_t
- __pthread_self (void)
- {
- return (pthread_t) THREAD_SELF;
- }
- strong_alias (__pthread_self, pthread_self)
- # define THREAD_SELF \
- ({ struct pthread *__self; \
- asm ("mov %%fs:%c1,%0" : "=r" (__self) \
- : "i" (offsetof (struct pthread, header.self))); \
- __self;})
- struct pthread
- {
- union
- {
- #if !TLS_DTV_AT_TP
- /* This overlaps the TCB as used for TLS without threads (see tls.h). */
- tcbhead_t header;
- #else
- struct
- {
- int multiple_threads;
- int gscope_flag;
- # ifndef __ASSUME_PRIVATE_FUTEX
- int private_futex;
- # endif
- } header;
- #endif
- typedef struct
- {
- void *tcb; /* Pointer to the TCB. Not necessarily the
- thread descriptor used by libpthread. */
- dtv_t *dtv;
- void *self; /* Pointer to the thread descriptor. */
- int multiple_threads;
- int gscope_flag;
- uintptr_t sysinfo;
- uintptr_t stack_guard;
- uintptr_t pointer_guard;
- unsigned long int vgetcpu_cache[2];
- # ifndef __ASSUME_PRIVATE_FUTEX
- int private_futex;
- # else
- int __glibc_reserved1;
- # endif
- int rtld_must_xmm_save;
- /* Reservation of some values for the TM ABI. */
- void *__private_tm[4];
- /* GCC split stack support. */
- void *__private_ss;
- long int __glibc_reserved2;
- /* Have space for the post-AVX register size. */
- __128bits rtld_savespace_sse[8][4] __attribute__ ((aligned (32)));
- void *__padding[8];
- } tcbhead_t;
- #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区别的更多相关文章
- gettid()和pthread_self()的区别
Linux中,每个线程有一个tid,类型long,由sys_gettid()取得. Linux内核中并没有实现线程,而是由glibc线程库实现的POSIX线程.每个线程也有一个id,类型 pthrea ...
- gettid 和pthread_self的区别
转: Linux中,每个进程有一个pid,类型pid_t,由getpid()取得.Linux下的POSIX线程也有一个id,类型 pthread_t,由pthread_self()取得,该id由线程库 ...
- getpid 与 gettid 与 pthread_self
获取进程的PID(process ID) #include <unistd.h> pid_t getpid(void); 获取线程的TID(thread ID) 1)gettid或者类似g ...
- linux的pthread_self与gettid的返回值和开销的区别
linux的pthread_self与gettid的返回值和开销的区别 linux的pthread_self与gettid的返回值和开销的区别 分类: 一些思考 2012-05-18 12:25 17 ...
- Linux下获取线程TID的方法——gettid()
(转载)http://blog.csdn.net/delphiwcdj/article/details/8476547 如何获取进程的PID(process ID)? 可以使用: #include & ...
- c#与java的区别
经常有人问这种问题,用了些时间java之后,发现这俩玩意除了一小部分壳子长的还有能稍微凑合上,基本上没什么相似之处,可以说也就是马甲层面上的相似吧,还是比较短的马甲... 一般C#多用于业务系统的开发 ...
- jquery和Js的区别和基础操作
jqery的语法和js的语法一样,算是把js升级了一下,这两种语法可以一起使用,只不过是用jqery更加方便 一个页面想要使用jqery的话,先要引入一下jqery包,jqery包从网上下一个就可以, ...
- 【原】nodejs全局安装和本地安装的区别
来微信支付有2年多了,从2年前的互联网模式转变为O2O模式,主要的场景是跟线下的商户去打交道,不像以往的互联网模式,有产品经理提需求,我们帮忙去解决问题. 转型后是这样的,团队成员更多需要去寻找业务的 ...
- 探究@property申明对象属性时copy与strong的区别
一.问题来源 一直没有搞清楚NSString.NSArray.NSDictionary--属性描述关键字copy和strong的区别,看别人的项目中属性定义有的用copy,有的用strong.自己在开 ...
随机推荐
- 【转帖】Alpha、Beta、RC、GA版本的区别
[版本]Alpha.Beta.RC.GA版本的区别 https://www.jianshu.com/p/d69226decbfe Alpha:是内部测试版,一般不向外部发布,会有很多Bug.一般只有测 ...
- Java 在 Word 文档中使用新文本替换指定文本
创作一份文案,经常会高频率地使用某些词汇,如地名.人名.人物职位等,若表述有误,就需要整体撤换.文本将介绍如何使用Spire.Doc for Java,在Java程序中对Word文档中的指定文本进行替 ...
- 【chromium】 cef源码下载
至少需要17GB的磁盘空间,不光有CEF源码,还会下载chromium源码.编译master分支的话,如果编译到chromium可能会需要windows sdk,windows sdk的版本可以参考下 ...
- golang开始篇
一 First Golang 1.1 需求 第一个程序hello.go,可以输出"hello golang" 1.2 开发步骤 开发这个程序时,我们的目录结构怎么处理(让自己或 ...
- 报错 xxx@1.0.0 dev D:\> webpack-dev-server --inline --progress --configbuild/webpack.dev.conf.js
是因为node_modules有意外改动,导致依赖库不完整. 解决:1.删除项目下的node_modules,在你的项目目录下 重新执行npm install,这会重新生成node_modules, ...
- In-Memory:哈希索引
SQL Server 2016支持哈希查找,用户可以在内存优化表(Memory-Optimized Table)上创建哈希索引(Hash Index),使用Hash 查找算法,实现数据的极速查找.在使 ...
- DBA职业发展之路:去“IOE”等挑战之下,DBA将何去何从?
DBA职业发展之路:去“IOE”等挑战之下,DBA将何去何从? 摘要:随着近些年来,开源.自动化.云化的兴起,DBA职业也正悄然发生一些变化.面对一系列新的挑战,DBA将如何进行职业发展?本文将给出一 ...
- Tomcat 对静态资源的处理
Tomcat 中的请求都是由 Servlet 处理,静态资源也不例外.在默认的 web.xml 中,配置了一个 DefaultServlet 用于处理静态资源,它支持缓存和断点续传. DefaultS ...
- Django---Django的中间件
Django---Django的中间件 一丶中间件介绍 什么是中间件 官方的说法:中间件是一个用来处理Django的请求和响应的框架级别的钩子.它是一个轻量.低级别的插件系统,用于在全局范围内改变Dj ...
- 92.vue---新手从本地项目开发到服务器线上运行爬坑。
因为我做的是后台,所以不用做SEO 参考 本项目的定位是后台集成方案,不太适合当基础模板来进行二次开发.因为本项目集成了很多你可能用不到的功能,会造成不少的代码冗余.如果你的项目不关注这方面的问题,也 ...