注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

天马行空

宠辱不惊,闲看庭前花开花落;去留无意,漫观天外云展云舒……

 
 
 

日志

 
 
 
 

Linux上获得线程id的方法  

2011-11-11 10:30:20|  分类: LINUX |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

在Linux上获得线程id的方法我使用了第二种方法,很方便:

#define gettid() syscall(__NR_gettid)

用到的地方 gettid()

在Linux2.4版本后,Linux使用了NPTL作为自己的线程库,为了兼容POSIX标准,所以在内核task中有两个域tgid和tid, 前者是进程id,后者是线程id。在Linux上获得线程id的方法,目前我所知的有三种,当然这里的三种是指在用户态的程序中,否则除非自己写的 kernel module, 都是调用编号224的系统调用实现的(2.6版本)。

第一种: gettid(), man gettid 可以看到gettid的使用方式。

使用时要先定义:_syscall0(pid_t, gettid)

其中_syscall0是一个宏(由于参数的不同还有_syscall1,_syscall2...),定义如下:

#define _syscall0(type,name) \ 
type name(void) \ 
{ \ 
long __res; \ 
__asm__ volatile ("int $0x80" \ //int 80, 软中断 
: "=a" (__res) \ //输入输出都用的eax 
: "0" (__NR_##name)); \ //#define __NR_gettid 224 
__syscall_return(type,__res); \ //返回tid 
}


编译时,宏展开之后,相当于定义了一个pid_t gettid(void)函数,用内嵌汇编实现,在程序中就可以使用gettid()获得线程id了。

完整结构如下:

#include "sys/types.h"
#include "unistd.h"
#include "sys/syscall.h"

#define gettid() syscall(__NR_gettid)

#define _syscall0(type,name) \
type name(void) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name)); \
__syscall_return(type,__res);\
}

第二种:syscall(), 名字叫syscall(),却是glibc中的库函数。

使用方式:syscall(__NR_gettid), 其中__NR_gettid就是224,同上。

syscall的实现要到glibc中去找,不同的硬件平台有不同的实现版本,在i386上的实现在syscall.S中:

#include 
.text 
ENTRY (syscall) 
PUSHARGS_6 /* Save register contents. */ 
_DOARGS_6(44) /* Load arguments. */ 
movl 20(%esp), %eax /* Load syscall number into %eax. */ 
ENTER_KERNEL /* Do the system call. */ 
POPARGS_6 /* Restore register contents. */ 
cmpl $-4095, %eax /* Check %eax for error. */ 
jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */ 
L(pseudo_end): 
ret /* Return to caller. */ 
PSEUDO_END (syscall)


其中ENTRY也是一个宏,展开了相当的长,主要用于在链接的时候让gcc能够"看见"并调用这段用汇编写成的syscall()函数。

第三种:pthread_self()

同样是一个glibc提供的函数,在Linux的manual中说返回的是当前线程的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,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了。

相比前两种做法,这种无疑是最繁琐的,但是同理,可以获取很多glibc中维护了,但是没有提供访问方法的数据。
  评论这张
 
阅读(1162)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018