如何打印pthread_t

dim*_*mba 50 c c++ linux pthreads

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

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

你是如何在你的应用程序中做到的?

更新:

其实我不需要pthread_t,而是一些小的数字id,在调试消息中识别不同的线程.

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

sth*_*sth 34

这将打印出a的十六进制表示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]));
  }
}
Run Code Online (Sandbox Code Playgroud)

只需打印一个小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];
}
Run Code Online (Sandbox Code Playgroud)

根据平台及其实际表示,pthread_t可能需要定义operator<for pthread_t,因为std::map需要对元素进行排序:

bool operator<(const pthread_t &left, const pthread_t &right) {
  ...
}
Run Code Online (Sandbox Code Playgroud)


Emp*_*ian 24

GDB在Linux上使用thread-id(又名内核pid,又名LWP)作为短数字.尝试:

  #include <syscall.h>
  ...

    printf("tid = %d\n", syscall(SYS_gettid));
Run Code Online (Sandbox Code Playgroud)

  • 在Linux上,pthread_t和LWP之间存在1:1的映射.您将永远不会获得相同的线程来报告其生命周期中不同点的不同LWP. (4认同)
  • 谢谢!使用%lu来避免使用gcc -Wall发出警告 (2认同)

Jam*_*lis 16

在这种情况下,它取决于操作系统,因为POSIX标准不再需要pthread_t是算术类型:

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

您需要查看sys/types.h标题,看看如何pthread_t实现; 然后你可以打印出你认为合适的方式.由于没有可移植的方法来执行此操作,并且您没有说明您正在使用的操作系统,因此没有更多内容可以说.

编辑:为了回答您的新问题,每次新线程启动时,GDB都会分配自己的线程ID:

出于调试目的,gdb将自己的线程号 - 始终是一个整数 - 与程序中的每个线程相关联.

如果您正在考虑在每个线程内打印一个唯一的数字,那么最干净的选择可能是告诉每个线程启动它时使用的数字.


Rom*_*nko 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;
}
Run Code Online (Sandbox Code Playgroud)

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()));
Run Code Online (Sandbox Code Playgroud)

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

在日志记录期间调用pthread_self()并搜索内部表,如果它知道线程.如果创建了具有此类ID的线程,则使用其索引(或从先前的线程重新使用,实际上并不重要,因为同一时刻没有2个相同的ID).如果尚未知道线程ID,则创建新条目以生成/使用新索引.

优点是简单.缺点是没有跟踪线程创建/销毁.因此,要跟踪这一点,需要一些外部机制.