对于linux中线程id的讨论

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zeqi1991/article/details/81611919

在LINUX系统中,POSIX threads库提供了pthread_t来标识一个线程,通过pthread_self()可以得到,如下:

#include <iostream>
#include <pthread.h>

using namespace std;

void* thread_func(void*)
{
    //pthread_t other_thread_id = pthread_self();
    //cout << "other_thread_id=" << other_thread_id << endl;
    return NULL;
}


int main(int argc, char *argv[])
{
    pthread_t t1, t2;
    pthread_create(&t1, NULL, thread_func, NULL);
    cout << t1 << endl;
    pthread_join(t1, NULL);

    //pthread_create(&t2, NULL, thread_func, NULL);
    //cout << t2 << endl;
    //pthread_join(t2, NULL);
    return 0;
}

得到结果:
这里写图片描述
typedef unsigned long int pthread_t;
这个数值很大。而且比较两个线程是否相同也需要用pthread_equal(pthread_t t1, pthread_t t2)来比较。

那么,使用pthread_t来标识线程id是否是最合适的?
答案是否
原因:这个pthread_t的值很大,无法作为一些容器的key值。
pthread_t是由POSIX pthread库内部提供的,只在进程内部有意义,无法关联操作系统的任务调度之类的信息。比方说在/proc查找不到关于pthread_t得到的task。
glibc的Pthreads实现实际上把pthread_t作为一个结构体指针,指向一块动态分配的内存,但是这块内存是可以反复使用的,也就是说很容易造成pthread_t的重复。也就是说pthreads只能保证同一进程内,同一时刻的各个线程不同;不能保证同一个进程全程时段每个线程具有不同的id,不能保证线程id的唯一性。下面可以通过一个例子:

#include <iostream>
#include <pthread.h>

using namespace std;

void* thread_func(void*)
{
    //pthread_t other_thread_id = pthread_self();
    //cout << "other_thread_id=" << other_thread_id << endl;
    return NULL;
}


int main(int argc, char *argv[])
{
    pthread_t t1, t2;
    pthread_create(&t1, NULL, thread_func, NULL);
    cout << t1 << endl;
    pthread_join(t1, NULL);

    pthread_create(&t2, NULL, thread_func, NULL);
    cout << t2 << endl;
    pthread_join(t2, NULL);
    return 0;
}

运行结果:
这里写图片描述

上述原因显然表明pthread_t是不适合作为线程的标识的。所以应该使用什么来标识呢。
首先对于进程id,有函数getpid返回的pid_t来标识。那么线程有没有类似的gettid来标识呢。
在LINUX系统中,建议使用gettid系统调用的返回值作为线程id,这么做的原因:
返回值是一个pid_t,其值是一个很小的整数,方便输出。
在linux系统中,它直接标识内核任务调度id,可通过/proc文件系统中找到对应项:/proc/tid 或者 /proc/pid/task/tid,方便定位到具体线程
任何时刻都是唯一的,并且由于linux分配新的pid采用递增轮回办法,短时间内启动多个线程也会具有不同的id
0是非法值,操作系统第一个进程init的pid是1

glibc没有封装这个gettid,需要我们手动封装。
举例:

#include <iostream>
#include <pthread.h>
#include <sys/syscall.h>//获取线程id的系统调用头文件
#include <sys/types.h>
#include <unistd.h>

using namespace std;

void* thread_func(void*)
{
    //获取线程id的系统调用
    cout << syscall(__NR_gettid) << endl;
    return NULL;
}


int main(int argc, char *argv[])
{
    pthread_t t1, t2;
    pthread_create(&t1, NULL, thread_func, NULL);
    cout << t1 << endl;
    pthread_join(t1, NULL);

    pthread_create(&t2, NULL, thread_func, NULL);
    cout << t2 << endl;
    pthread_join(t2, NULL);
    return 0;
}

结果:
这里写图片描述
和pthread_t的描述完全不一样。

使用比较优雅的方式是定义一个gettid的宏

#include <sys/syscall.h>//获取线程id的系统调用头文件
#include <sys/types.h>
#include <unistd.h>

//定义宏
#define gettid() syscall(__NR_gettid)

验证TID是否正确的方法:
查看进程pid
(1) ps ux | grep prog_name
(2) pgrep prog_name
查看线程tid
(1) ps -efL | grep prog_name
(2) ls /proc/pid/task

猜你喜欢

转载自blog.csdn.net/zeqi1991/article/details/81611919
今日推荐