为何修改pthread_getattr_default_np返回的pthread_attr_t会影响全局默认属性?
Linux下pthread_getattr_default_np与pthread_attr_setaffinity_np的意外行为问题
在Linux环境下使用pthread_getattr_default_np()和pthread_attr_setaffinity_np()时遇到不符合预期的行为:
- 通过
pthread_setattr_default_np()设置了基于当前线程CPU亲和性的全局默认线程属性 - 调用
pthread_getattr_default_np()将默认属性存入变量attr1,随后修改attr1的CPU亲和性为仅CPU3 - 预期仅
attr1会受影响,但再次调用pthread_getattr_default_np()得到的attr2也被设置为仅CPU3,全局默认属性被意外修改
示例代码
#include <pthread.h> #include <stdio.h> void display_pthread_attr(pthread_attr_t* attr, const char* label) { cpu_set_t cpuset; int ret = pthread_attr_getaffinity_np(attr, sizeof(cpu_set_t), &cpuset); if (ret != 0) { printf("%s: Failed to get CPU affinity (error %d)\n", label, ret); return; } printf("%s CPU SET: ", label); for (int i = 0; i < CPU_SETSIZE; ++i) { if (CPU_ISSET(i, &cpuset)) { printf("%d ", i); } } printf("\n"); } void overrideDefaultThreadAttribute() { pthread_attr_t* attribute = new pthread_attr_t; pthread_attr_init(attribute); cpu_set_t cpuSet; pthread_getaffinity_np(pthread_self(), sizeof(cpuSet), &cpuSet); pthread_attr_setaffinity_np(attribute, sizeof(cpu_set_t), &cpuSet); pthread_setattr_default_np(attribute); display_pthread_attr(attribute, "OverrideDefaultThreadAttribute"); } int main() { overrideDefaultThreadAttribute(); pthread_attr_t attr1, attr2; pthread_getattr_default_np(&attr1); display_pthread_attr(&attr1, "Default attr1"); // Modify attr1 cpu_set_t cpus; CPU_ZERO(&cpus); CPU_SET(3, &cpus); pthread_attr_setaffinity_np(&attr1, sizeof(cpu_set_t), &cpus); display_pthread_attr(&attr1, "attr1 pinned to 3"); // Get another default attribute pthread_getattr_default_np(&attr2); display_pthread_attr(&attr2, "Default attr2"); }
输出结果
OverrideDefaultThreadAttribute CPU SET: 0 1 2 3 4 5 6 18 19 20 21 22 23 24 Default attr1 CPU SET: 0 1 2 3 4 5 6 18 19 20 21 22 23 24 attr1 pinned to 3 CPU SET: 3 Default attr2 CPU SET: 3
问题原因
pthread_getattr_default_np()返回的是指向全局默认属性对象的直接引用,而非独立副本。当你修改通过该函数获取到的pthread_attr_t变量时,实际上是直接操作全局默认属性的内存区域,因此修改会同步影响后续获取的默认属性。
解决方案
若要修改默认属性的副本而不影响全局设置,需先初始化新的属性对象,再通过pthread_attr_copy()复制默认属性到新对象,之后对副本进行修改:
// 正确用法示例 pthread_attr_t attr_copy; pthread_attr_init(&attr_copy); // 初始化新属性对象 pthread_attr_t default_attr; pthread_getattr_default_np(&default_attr); pthread_attr_copy(&attr_copy, &default_attr); // 复制默认属性到副本 // 修改副本,不会影响全局默认属性 cpu_set_t cpus; CPU_ZERO(&cpus); CPU_SET(3, &cpus); pthread_attr_setaffinity_np(&attr_copy, sizeof(cpu_set_t), &cpus);
另外,原代码中overrideDefaultThreadAttribute()函数动态分配pthread_attr_t后未调用pthread_attr_destroy()释放资源,会导致内存泄漏,需补充释放逻辑:
void overrideDefaultThreadAttribute() { pthread_attr_t* attribute = new pthread_attr_t; pthread_attr_init(attribute); // ... 原有逻辑 ... pthread_attr_destroy(attribute); // 销毁属性对象 delete attribute; // 释放动态分配的内存 }
内容的提问来源于stack exchange,提问作者sys
相关产品推荐
相关产品推荐

