如何打印 pthread_t
- 2024-10-29 08:35:00
- admin 原创
- 64
问题描述:
搜索过,但没有找到令人满意的答案。
我知道没有可移植的方法来打印 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
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件