如何打印 pthread_t

2024-10-29 08:35:00
admin
原创
64
摘要:问题描述:搜索过,但没有找到令人满意的答案。我知道没有可移植的方法来打印 pthread_t。您如何在您的应用程序中做到这一点?更新: 实际上我不需要 pthread_t,而是需要一些小的数字 id,在调试消息中识别不同的线程。在我的系统(64 位 RHEL 5.3)上,它被定义为无符号长整型,因此它是一个很...

问题描述:

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

我知道没有可移植的方法来打印 pthread_t。

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

更新:

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

在我的系统(64 位 RHEL 5.3)上,它被定义为无符号长整型,因此它是一个很大的数字,而仅仅打印它会占用调试行中的宝贵位置。 gdb如何分配短 tid?


解决方案 1:

这将打印出 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]));
  }
}

为了只打印每个小的 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这里可能需要定义一个operator<for pthread_t,因为std::map需要对元素进行排序:

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

解决方案 2:

GDB 在 Linux 上使用线程 ID(又名内核 pid,又名 LWP)作为短数字。尝试:

  #include <syscall.h>
  ...

    printf("tid = %d
", syscall(SYS_gettid));

解决方案 3:

在这种情况下,它取决于操作系统,因为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 将其自己的线程号(始终是一个整数)与程序中的每个线程关联。

如果您希望在每个线程内打印一个唯一的编号,那么最干净的选择可能是告诉每个线程在启动时使用什么编号。

解决方案 4:

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

  • 如何获取用于日志记录的线程的更短的唯一 ID。

  • 无论如何,我们需要打印线程的真实 pthread_t ID(至少只是为了链接到 POSIX 值)。

1.打印POSIX ID(pthread_t)

您可以简单地将 pthread_t 视为字节数组,每个字节打印十六进制数字。因此,您不受某些固定大小类型的限制。唯一的问题是字节顺序。您可能希望打印的字节顺序与打印的简单“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
", 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 未知,则创建新条目,从而生成/使用新索引。

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

解决方案 5:

在 Centos 5.4 x86_64 上,pthread_t 是无符号长整型的 typedef。

因此,我们可以这样做...

#include <iostream>
#include <pthread.h>

int main() {
    pthread_t x;
    printf("%li
", (unsigned long int) x);
    std::cout << (unsigned long int) x << "
";
}

解决方案 6:

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

int get_tid(pthread_t tid)
{
    assert_fatal(sizeof(int) >= sizeof(pthread_t));

    int * threadid = (int *) (void *) &tid;
    return *threadid;
}

解决方案 7:

你可以做这样的事情:

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!
", 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!
", 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!
", thread_id);
    return NULL;
}

这样做的好处是您不必在函数调用中传递thread_id,但它在Mac OS等上不起作用。

解决方案 8:

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

创建字节的哈希值pthread_t(无论是结构、指针、长整数还是其他)可能是一种有用的解决方案,不需要查找表。与任何哈希值一样,也存在发生冲突的风险,但您可以调整哈希值的长度以满足您的要求。

解决方案 9:

我知道,这个帖子很老了。读完以上所有帖子后,我想再补充一个想法,以便以一种巧妙的方式处理这个问题:如果你无论如何都要进入映射业务(将 pthread_to 映射到 int),那么你也可以在可读性方面更进一步。让你的 pthread_create_wrapper 也接受一个字符串……线程的名称。我学会了欣赏 Windows 和 Windows CE 上的这个“SetThreadName()”功能。优点:你的 ID 不仅仅是数字,而且你还可以看到你的哪个线程有什么用途。

解决方案 10:

您可以尝试将其转换为无符号短整型,然后仅打印最后四位十六进制数字。结果值可能足够独特,可以满足您的需求。

解决方案 11:

不需要太花哨,你可以将其pthread_t视为一个不需要强制转换的指针:

printf("awesome worker thread id %p
", awesome_worker_thread_id);

输出:

优秀工作线程 ID 0x6000485e0

解决方案 12:

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

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

无论何时想要打印pthread_t,创建一个tid并分配tid.pthread_id = ...,然后打印tid.converted_id

解决方案 13:

正如詹姆斯上面提到的,最好的方法是查看定义类型的标题。

您可以在pthreadtypes.h中找到pthread_t的定义,其位置如下:

/usr/include/bits/pthreadtypes.h

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用