搜索,但没有遇到令人满意的答案。
我知道没有一种可移植的方式来打印pthread_t。
你如何在你的应用程序中做到这一点?
更新:
实际上我不需要pthread_t,而是一些小的数字id,在调试消息中标识不同的线程。
在我的系统上(64位RHEL 5.3),它被定义为unsigned long int,因此它的数字很大,只是打印它在调试行中占有一席之地。 gdb如何分配短tid?
答案 0 :(得分:31)
这将打印出pthread_t
的十六进制表示,无论实际是什么:
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]));
}
}
要为每个pthread_t
打印一个小ID,可以使用这样的东西(这次使用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
的实际表示形式,可能需要为operator<
定义pthread_t
,因为std::map
需要对元素进行排序:
bool operator<(const pthread_t &left, const pthread_t &right) {
...
}
答案 1 :(得分:23)
GDB在Linux上使用thread-id(又名内核pid,又名LWP)作为短号。尝试:
#include <syscall.h>
...
printf("tid = %d\n", syscall(SYS_gettid));
答案 2 :(得分:14)
在这种情况下,它取决于操作系统,因为the POSIX standard no longer requires pthread_t
to be an arithmetic type:
IEEE Std 1003.1-2001 / Cor 2-2004,应用项目XBD / TC2 / D6 / 26,将
pthread_t
添加到不需要算术类型的类型列表中,从而允许{{1被定义为结构。
您需要查看pthread_t
标题,了解sys/types.h
的实施方式;然后你可以打印出你认为合适的方式。由于没有可移植的方法来执行此操作,并且您没有说明您正在使用的操作系统,因此没有更多的话要说。
修改:回答您的新问题GDB assigns its own thread ids each time a new thread starts:
出于调试目的,gdb将自己的线程号 - 始终是一个整数 - 与程序中的每个线程相关联。
如果您正在考虑在每个线程中打印一个唯一的数字,那么最干净的选择可能是告诉每个线程在启动它时使用的数字。
答案 3 :(得分:7)
好的,这似乎是我的最终答案。我们有两个实际问题:
<强> 1。打印POSIX ID(pthread_t)
您可以简单地将pthread_t视为每个字节打印十六进制数字的字节数组。因此,您不受某些固定大小类型的限制。唯一的问题是字节顺序。您可能喜欢如果打印字节的顺序与打印的简单“int”相同。这是little-endian的示例,对于big-endian,只有订单应该被还原(在define下):
#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
在任何建议的情况下,您应该将实际线程ID(posix)转换为某个表的索引。但是有两种截然不同的方法:
<强> 2.1。跟踪线程。
你可以跟踪表中所有现有线程的线程ID(它们的pthread_create()调用应该被包装)并且具有“重载”id函数,它只能获得表索引,而不是真正的线程ID。此方案对于任何内部线程相关的调试和资源跟踪也非常有用。显而易见的优点是线程级跟踪/调试工具的副作用,可能进一步扩展。缺点是需要跟踪任何线程创建/销毁。
这是部分伪代码示例:
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。
在日志记录期间调用pthread_self()并搜索内部表,如果它知道线程。 如果创建了具有此类ID的线程,则使用其索引(或从先前的线程重新使用,实际上并不重要,因为同一时刻没有2个相同的ID)。如果尚未知道线程ID,则创建新条目以生成/使用新索引。
优点是简单。缺点是没有跟踪线程创建/销毁。因此,要跟踪这一点,需要一些外部机制。
答案 4 :(得分:4)
在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";
}
答案 5 :(得分:3)
你可以这样做:
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上。
答案 6 :(得分:3)
如果pthread_t只是一个数字;这将是最简单的。
int get_tid(pthread_t tid)
{
assert_fatal(sizeof(int) >= sizeof(pthread_t));
int * threadid = (int *) (void *) &tid;
return *threadid;
}
答案 7 :(得分:2)
查找表(pthread_t : int)
可能会成为启动大量短期线程的程序中的内存泄漏。
创建pthread_t
的字节的散列(无论是结构,指针还是长整数或其他)可能是一个不需要查找表的可用解决方案。与任何哈希一样,存在冲突风险,但您可以调整哈希的长度以满足您的要求。
答案 8 :(得分:1)
您可以尝试将其转换为无符号短文,然后仅打印最后四个十六进制数字。结果值可能足以满足您的需求。
答案 9 :(得分:1)
我知道,这个帖子很老了。阅读完所有上述帖子后,我想再添加一个想法,以便以一种简洁的方式处理这个问题: 如果你无论如何进入映射业务(将pthread_to映射到int),你还可以在可读性方面更进一步。使你的pthread_create_wrapper使得它也需要一个字符串......线程的名称。 我学会了在Windows和Windows CE上欣赏这个“SetThreadName()”功能。 优点:您的ID不仅仅是数字,而且您还可以看到,您的哪些线程具有哪些目的。
答案 10 :(得分:0)
只是对第一篇文章的补充:使用用户定义的联合类型来存储pthread_t:
union tid {
pthread_t pthread_id;
unsigned long converted_id;
};
每当您想要打印pthread_t
时,请创建tid
并指定tid.pthread_id = ...
,然后打印tid.converted_id
。
答案 11 :(得分:0)
如上所述,James最好的方法是查看定义类型的标头。
您可以在 pthreadtypes.h 中找到 pthread_t 的定义,该定义位于:
/usr/include/bits/pthreadtypes.h
答案 12 :(得分:0)
不需要花哨的地方,您可以将pthread_t
视为没有强制转换的指针:
printf("awesome worker thread id %p\n", awesome_worker_thread_id);
输出:
很棒的工作线程ID 0x6000485e0