如何打印pthread_t

search,但没有遇到一个令人满意的答案。

我知道没有一种便携的方式来打印pthread_t。

你如何在你的应用程序中做到这一点?

更新:

其实我不需要pthread_t,但一些小的数字ID,在debugging消息中标识不同的线程。

在我的系统上(64位RHEL 5.3),它被定义为unsigned long int,所以它是大数字,只是打印它在debugging行中吃了一个宝贵的地方。 gdb如何分配 short tids?

这将打印一个pthread_t的hex表示,不pipe实际是什么:

 void fprintPt(FILE *f, pthread_t pt) { unsigned char *ptc = (unsigned char*)(void*)(&pt); fprintf(f, "0x"); for (size_t i=0; i<sizeof(pt); i++) { fprintf(f, "%02x", (unsigned)(ptc[i])); } } 

只要打印一个小的id为每个pthread_t可以使用(这次使用iostreams):

 void printPt(std::ostream &strm, pthread_t pt) { static int nextindex = 0; static std::map<pthread_t, int> ids; if (ids.find(pt) == ids.end()) { ids[pt] = nextindex++; } strm << ids[pt]; } 

根据平台和pthread_t的实际表示,可能需要为pthread_t定义一个operator<因为std::map需要对元素进行sorting:

 bool operator<(const pthread_t &left, const pthread_t &right) { ... } 

GDB在Linux上使用thread-id(也称为内核pid,又名LWP)作为短号。 尝试:

  #include <syscall.h> ... printf("tid = %d\n", syscall(SYS_gettid)); 

在这种情况下,它依赖于操作系统,因为POSIX标准不再要求pthread_t是一种算术types :

IEEE Std 1003.1-2001 / Cor 2-2004中,应用了项目XBD / TC2 / D6 / 26,将pthread_t添加到不需要算术types的types列表中,从而允许将pthread_t定义为结构。

你需要查看你的sys/types.h头文件,看看pthread_t是如何实现的。 那么你可以打印它,你觉得合适。 由于没有可移植的方法来执行此操作,而且您也不会说使用的操作系统,所以没有太多可说的地方。

编辑:为了回答你的新问题, 每当一个新的线程启动时 , GDB分配它自己的线程id :

为了进行debugging,gdb将自己的线程号(总是一个整数)与程序中的每个线程关联起来。

如果你打算在每个线程中打印一个唯一的数字,那么你最干净的选项可能是告诉每个线程在启动时使用的数字。

好的,看来这是我的最终答案。 我们有两个实际的问题:

  • 如何为线程获取更短的唯一ID进行logging。
  • 无论如何,我们需要为线程打印真正的pthread_t ID(至less链接到POSIX值)。

1.打印POSIX ID(pthread_t)

您可以简单地将pthread_t作为每个字节打印hex数字的字节数组。 所以你不受限于一些固定大小的types。 唯一的问题是字节顺序。 你可能喜欢,如果你打印的字节顺序是打印简单的“int”相同。 这里是小端的例子,只有大端的顺序才能被恢复(定义下):

 #include <pthread.h> #include <stdio.h> void print_thread_id(pthread_t id) { size_t i; for (i = sizeof(i); i; --i) printf("%02x", *(((unsigned char*) &id) + i - 1)); } int main() { pthread_t id = pthread_self(); printf("%08x\n", id); print_thread_id(id); return 0; } 

2.获取较短的可打印的线程ID

在任何build议的情况下,您都应该将真实的线程ID(posix)转换为某个表的索引。 但有两种截然不同的方法:

2.1。 跟踪线程。

您可以跟踪表中所有现有线程的线程ID(它们的pthread_create()调用应该被包装)并且具有“重载”的id函数,使您只是表索引,而不是真正的线程ID。 此scheme对于任何内部线程相关的debugging资源跟踪也非常有用。 线程级跟踪/debugging设施的副作用是未来扩展的可能。 缺点是需要跟踪任何线程的创build/销毁。

这里是部分伪代码示例:

 pthread_create_wrapper(...) { id = pthread_create(...) add_thread(id); } pthread_destruction_wrapper() { /* Main problem is it should be called. pthread_cleanup_*() calls are possible solution. */ remove_thread(pthread_self()); } unsigned thread_id(pthread_t known_pthread_id) { return seatch_thread_index(known_pthread_id); } /* user code */ printf("04x", thread_id(pthread_self())); 

2.2。 只需注册新的线程ID。

在日志logging期间调用pthread_self()并search内部表,如果它知道线程。 如果创build了这样的ID的线程,它的索引被使用(或从以前的线程中重用,实际上并不重要,因为同一时刻没有2个相同的ID)。 如果线程ID还不知道,则会创build新条目,以便生成/使用新索引。

优点是简单。 缺点是没有线程创build/销毁的跟踪。 所以要跟踪这个需要一些外部机制。

在Centos 5.4 x86_64上,pthread_t是unsigned long的typedef。

因此,我们可以这样做…

 #include <iostream> #include <pthread.h> int main() { pthread_t x; printf("%li\n", (unsigned long int) x); std::cout << (unsigned long int) x << "\n"; } 

你可以做这样的事情:

 int thread_counter = 0; pthread_mutex_t thread_counter_lock = PTHREAD_MUTEX_INITIALIZER; int new_thread_id() { int rv; pthread_mutex_lock(&thread_counter_lock); rv = ++thread_counter; pthread_mutex_unlock(&thread_counter_lock); return rv; } static void *threadproc(void *data) { int thread_id = new_thread_id(); printf("Thread %d reporting for duty!\n", thread_id); return NULL; } 

如果你可以依靠GCC(clang也可以在这种情况下工作),你也可以这样做:

 int thread_counter = 0; static void *threadproc(void *data) { int thread_id = __sync_add_and_fetch(&thread_counter, 1); printf("Thread %d reporting for duty!\n", thread_id); return NULL; } 

如果你的平台支持这个,一个类似的选项:

 int thread_counter = 0; int __thread thread_id = 0; static void *threadproc(void *data) { thread_id = __sync_add_and_fetch(&thread_counter, 1); printf("Thread %d reporting for duty!\n", thread_id); return NULL; } 

这样做的好处是你不必在函数调用中绕过thread_id,但是它在Mac OS上不起作用。

如果pthread_t只是一个数字; 这将是最简单的。

 int get_tid(pthread_t tid) { assert_fatal(sizeof(int) >= sizeof(pthread_t)); int * threadid = (int *) (void *) &tid; return *threadid; } 

查找表(pthread_t : int)可能会在启动大量短暂线程的程序中变成内存泄漏。

创build一个pthread_t (无论是结构体,指针还是长整型或其他)的字节散列可能是一个不需要查找表的可用解决scheme。 与任何散列一样,存在冲突的风险,但您可以调整散列的长度以适应您的要求。

你可以尝试把它转换成一个无符号的short,然后打印最后四个hex数字。 由此产生的价值可能足以满足您的需求。

我知道,这个线程是非常古老的。 阅读了上面的所有post之后,我想再添加一个想法来以一种简洁的方式处理这个问题:无论如何,如果你进入了映射业务(将pthread_to映射到一个int),那么你可以更进一步的可读性。 使你的pthread_create_wrapper这样也需要一个string…线程的名称。 我学会了欣赏Windows和Windows CE上的“SetThreadName()”function。 优点:你的ID不只是数字,但你也看到,你的哪个线程有什么目的。

只是对第一篇文章的补充:使用用户定义的联合types来存储pthread_t:

 union tid { pthread_t pthread_id; unsigned long converted_id; }; 

每当你想打印pthread_t ,创build一个tid并分配tid.pthread_id = ... ,然后打印tid.converted_id