如何打印pthread_t

时间:2009-11-18 23:08:31

标签: c++ c linux pthreads

搜索,但没有遇到令人满意的答案。

我知道没有一种可移植的方式来打印pthread_t。

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

更新:

实际上我不需要pthread_t,而是一些小的数字id,在调试消息中标识不同的线程。

在我的系统上(64位RHEL 5.3),它被定义为unsigned long int,因此它的数字很大,只是打印它在调试行中占有一席之地。 gdb如何分配短tid?

13 个答案:

答案 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)

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

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

<强> 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