如何在Linux C程序中获取pthread的线程ID?

126
在Linux C程序中,如何打印由pthread库创建的线程的线程ID?例如,就像我们可以通过getpid()获得进程的PID一样。

12个回答

128

什么?此人要求Linux特定的,getpid()在BSD或Apple中没有等效项。答案是gettid()并返回整数类型。您需要使用syscall()调用它,像这样:

#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>

 ....

 pid_t x = syscall(__NR_gettid);

虽然这可能不适用于非Linux系统,但线程 ID 是可以直接进行比较且获取速度非常快的。它可以像普通整数一样打印(例如用于 LOGs)。


18
这应该是正确的答案。 - Matthew S
2
这个人询问了在Linux上能否运行某些东西。以可移植的方式实现似乎是我认为更好的方式。如果可移植性不重要,那么我猜Linux真的正在成为新的Windows... - Jasper Siepkes
5
你没有抓住重点。他询问的是与 getpid() 等效的线程 LINUX 调用,即 gettid()。这个问题并没有要求可移植性或 POSIX。太多人想炫耀和教训别人,而不是回答真正的问题。pthread_self() 函数不能返回内核线程 ID,并且不能轻松打印其内容。此外,pthread_self 可能是一个指针,不应被操作,只能与 pthread_equal() 进行比较。该问题要求一个可以打印的 ID,而这就是 gettid()。 - Evan Langlois
4
他正在使用 pthread 库,字面上是 POSIX 线程库。因此,制作一个与 POSIX 兼容的答案并不奇怪。 "他要求一个类似于 getpid() 的 LINUX 调用,用于获取线程 id。" 不,getpid()只是举例而已,并没有说语义是硬规范。让人们意识到以符合 POSIX 的方式进行操作,这样除了 Linux 社区(如 FreeBSD、Illumos、OS X 等)外,其他社区也可以从中受益,这并不是在炫耀。就像我之前说的,我想 Linux 真的已经成为了下一个 Windows。 - Jasper Siepkes
2
在Linux Ubuntu 18.04上,使用gcc --version gcc (Ubuntu 8.4.0-1ubuntu1~18.04) 8.4.0,我不得不在所有的包含文件之前添加#define _GNU_SOURCE,以便定义syscall()。我从这里文档底部的示例中学到了这一点:https://man7.org/linux/man-pages/man2/syscall.2.html。 - Gabriel Staples
显示剩余6条评论

110

pthread_self()函数将返回当前线程的线程ID。

pthread_t pthread_self(void);

pthread_self()函数返回调用线程的Pthread句柄。pthread_self()函数不返回调用线程的整数线程。您必须使用pthread_getthreadid_np()返回线程的整数标识符。

注意:

pthread_id_np_t   tid;
tid = pthread_getthreadid_np();

速度明显快于这些调用,但提供相同的行为。

pthread_id_np_t   tid;
pthread_t         self;
self = pthread_self();
pthread_getunique_np(&self, &tid);

47
原问题与Linux有关。Linux不包括_np函数。(它不包含它们的手册页,我没有进一步检查。) - Trade-Ideas Philip
pthread_threadid_np 函数在 OS X >= 10.6 和 iOS >= 3.2 可用。 - bleater
@Bleater,能否提供pthread_threadid_np的官方文档?我需要在iOS和OSX平台上使用它,因此需要检查该API的可靠性。我已经参考了http://www.opensource.apple.com/source/Libc/Libc-583/pthreads/pthread.h上的链接,但不确定是否正确。 - Vivek Maran
@Vivek 我没有任何官方文档的链接,只有你提供的头文件和源代码在http://www.opensource.apple.com/source/Libc/Libc-583/pthreads/pthread.c。 - bleater
16
为了澄清,"_np"表示不可移植。Linux有自己的"_np"东西,但它不包括苹果的"pthread_getthreadid_np"。 - Josh Kelley
1
一些重要的注意事项:pthread_t 在 Linux 中是一种指针。因此,如果您多次运行相同的程序,则可能会看到相同的 pthread_t,而实际的线程是不同的。因此,打印 pthread_t 并没有太大帮助。 - U. Windl

25

正如其他答案所述,pthreads没有定义一个跨平台的方法来检索整数线程 ID。

在Linux系统上,您可以这样获取线程ID:

#include <sys/types.h>
pid_t tid = gettid();

在许多基于BSD的平台上,这个答案https://dev59.com/q2Ei5IYBdhLWcg3wpdjJ#21206357提供了一种非可移植的方法。

然而,如果你认为需要线程ID的原因是想知道自己是否正在和另一个可控线程运行在同一个线程中还是不同的线程中,那么你可能会在这种方法中找到一些实用性。

static pthread_t threadA;

// On thread A...
threadA = pthread_self();

// On thread B...
pthread_t threadB = pthread_self();
if (pthread_equal(threadA, threadB)) printf("Thread B is same as thread A.\n");
else printf("Thread B is NOT same as thread A.\n");

如果您只需要知道自己是否在主线程上,还有其他方法已在回答此问题的答案中记录 how can I tell if pthread_self is the main (first) thread in the process?


18
pid_t tid = syscall(SYS_gettid);

Linux 提供了这样的系统调用,允许您获取线程的 id。


3
根据这个回答,你需要包含#include <unistd.h>#include <sys/syscall.h> - ComFreek

10
你可以使用 pthread_self() 函数。
在成功执行 pthread_create() 后,父线程可以知道线程ID,但是在执行线程时,如果我们想要访问线程ID,则必须使用函数 pthread_self()

9

这一行代码可以为您提供进程ID,每个线程ID和SPID。

 printf("before calling pthread_create getpid: %d getpthread_self: %lu tid:%lu\n",getpid(), pthread_self(), syscall(SYS_gettid));

6

我认为不仅问题不清楚,大多数人也不了解其中的区别。看一下下面这句话:

POSIX线程ID并不同于Linux特有的gettid()系统调用返回的线程ID。 POSIX线程ID由线程实现分配和维护。由内核分配的是gettid()返回的线程ID号码(类似于进程ID)。尽管在Linux NPTL线程实现中,每个POSIX线程都有一个唯一的内核线程ID,但应用程序通常不需要知道内核ID(如果依赖于它们,将无法移植)。

摘自:The Linux Programming Interface: A Linux and UNIX System Programming Handbook, Michael Kerrisk

在我看来,只有一种可移植的方式可以将定义一个变量以升序保存数字的结构体传递给每个线程。通过这样做,可以跟踪线程的ID。然而,应该使用int pthread_equal(tid1, tid2)函数。
if (pthread_equal(tid1, tid2)) printf("Thread 2 is same as thread 1.\n");
else printf("Thread 2 is NOT same as thread 1.\n");

gettid()实际上是一个很好的建议,谢谢!但是,我需要遵循Sergey L.在这里的答案:https://dev59.com/aWEi5IYBdhLWcg3wb76O#21280941 - SRG

3

pthread_getthreadid_np 在我的 Mac os x 上不存在。 pthread_t 是一个不透明的类型。 不要过于纠结,只需将其分配给void*并调用即可。 如果需要使用printf,请使用%p


1
没错,这个可行。我只需要打印出来进行调试,所以0x23423423423abcdef和tid=1234一样有用。谢谢! - Qi Fan

1

还有一种获取线程ID的方法。在使用 int pthread_create(pthread_t * thread, const pthread_attr_t * attr, void * (*start_routine)(void *), void *arg); 函数创建线程时,第一个参数 pthread_t * thread 实际上是一个线程ID(在bits/pthreadtypes.h中定义为无符号长整型)。同时,最后一个参数 void *arg 是传递给 void * (*start_routine) 函数作为线程参数的参数。

您可以创建一个结构体来传递多个参数并发送指向结构体的指针。

typedef struct thread_info {
    pthread_t thread;
    //...
} thread_info;
//...
tinfo = malloc(sizeof(thread_info) * NUMBER_OF_THREADS);
//...
pthread_create (&tinfo[i].thread, NULL, handler, (void*)&tinfo[i]);
//...
void *handler(void *targs) {
    thread_info *tinfo = targs;
    // here you get the thread id with tinfo->thread
}

1

对于不同的操作系统,有不同的答案。我在这里找到了一个帮助程序这里

你可以尝试这个:

#include <unistd.h>
#include <sys/syscall.h>

int get_thread_id() {
#if defined(__linux__)
    return syscall(SYS_gettid);
#elif defined(__FreeBSD__)
    long tid;
    thr_self(&tid);
    return (int)tid;
#elif defined(__NetBSD__)
    return _lwp_self();
#elif defined(__OpenBSD__)
    return getthrid();
#else
    return getpid();
#endif
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接