我有一个 pthread_t,我想更改它的 CPU 关联性。问题是我使用的是 glibc 2.3.2,它没有 pthread_setaffinity_np()。不过没关系,因为 pthread_setaffinity_np() 本身就是 sched_setaffinity() 的包装器,可以通过传递线程 ID 而不是进程 ID 来调用它来设置任意线程的亲和性。
但是 ... sched_setaffinity 可以使用的线程 ID 是操作系统线程 ID,您可以从 gettid() 系统调用获取这种线程 ID。 这与不透明类型 pthread_t 不同,gettid() 只会返回当前线程的线程 ID。我需要能够设置任意线程的 CPU 亲和力。
不幸的是,我无法访问 pthread 的私有部分,这会让我通过将 pthread_t 转换为
struct pthread *
来窃取线程 id。我想这更好,因为依赖私有实现会带来更多更多麻烦。
我也一直在阅读 pthread_getunique_np 函数,但是这会返回一个“唯一的整数标识符”——我不认为它的形状或形式等同于操作系统线程 id。
因此,问题是:如何从任意 pthread_t 获取线程 ID?
由于
pthread
s 不需要使用 Linux 线程(或根本是内核线程)来实现,并且某些实现完全是用户级的或混合的,因此 pthread
s 接口不提供访问函数这些实现细节,因为它们不可移植(即使跨 Linux 上的 pthread
实现)。 使用这些的线程库可以提供它作为扩展,但似乎没有任何这样做。
除了访问线程库的内部数据结构(可以理解,您不希望这样做,尽管根据您对处理器关联性和 Linux 线程 ID 的假设,您的代码无论如何都不可移植),您也许可以在创建时玩点小把戏时间,如果您控制创建线程的代码:
给
pthread_create()
一个调用 gettid()
的入口函数(顺便说一句,您可能必须直接使用 syscall
宏,因为它并不总是由 libc
导出),将结果存储在某处,并且然后调用原来的入口函数。 如果您有多个具有相同入口函数的线程,则可以将递增的指针传递到 arg
参数中的数组中,然后将其传递给您创建的用于存储线程 ID 的入口函数。 pthread_create
以相同的顺序返回 pthread_t
的值,然后您将能够查找您创建的所有线程的 Linux 线程 ID。 pthread_create
值。这个技巧是否值得,取决于设置 CPU 关联性在您的情况下有多重要,而不是访问线程库的内部结构或取决于提供
pthread_t
的线程库。
pthread_setaffinity_np
返回
pthread_self
而不是您可以使用的整数线程 id,以下辅助函数将以可移植的方式跨不同 POSIX 系统为您提供该 ID。 pthread_t
中,返回的 uint64_t gettid() {
pthread_t ptid = pthread_self();
uint64_t threadId = 0;
memcpy(&threadId, &ptid, std::min(sizeof(threadId), sizeof(ptid)));
return threadId;
}
只是指向不透明
pthread_t
的指针。您可以在struct pthread
中查找定义。这个返回当前的pthread_t,即线程id,你可以将其转换为“unsigned int”类型,
希望有帮助。
pthread_t pthread_self()
函数来执行此操作。不幸的是,GNU LibC 目前还没有。
Bug 27880请求添加,但尚未实施。 macOS 还提供了
pthread_gettid_np
,尽管原型不同。但是,与此同时,您可以使用 pthread_gettid_np
库来完成此操作。请注意,库只能由调试器使用,因此从应用程序链接到它可能被认为是一种不好的做法。它还有一个相当复杂的 API——它是从 Solaris 复制的,它使用
thread_db
库来访问外部进程的内存;然而,在 Linux 上,预计 libproc
库函数不是由应用程序调用 libproc
API 来实现,而不是实现 libproc
。下面的示例代码仅实现了其工作所需的最低限度,并且仅适用于当前进程:thread_db