免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 980 | 回复: 0
打印 上一主题 下一主题

在linux上获得线程id的方法 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-07-16 15:23 |只看该作者 |倒序浏览
我使用了第二种方法,很方便:
#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了。
第二种: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中维护了,但是没有提供访问方法的数据。
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/28781/showart_1083438.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP