【发布时间】:2020-04-12 06:49:00
【问题描述】:
我有一个线程安全的函数,我想分配一个动态的线程本地内存缓冲区来独立使用它,并且一旦线程退出就能够释放它。这是演示:
void func_needs_storage(void) {
static __thread void* tlb = NULL;
if (!tlb)
tlb = malloc(sizeof(int));
printf("Thread id: %08lx, local tlb address is: %08lx\n",
(uintptr_t)pthread_self(), (uintptr_t)tlb);
}
void* thread_func(void *) {
for (int i = 0; i < 3; ++i)
func_needs_storage();
return NULL;
}
int main() {
pthread_t threads[3];
for (int i = 0; i < sizeof(threads) / sizeof(*threads); ++i)
if (pthread_create(&threads[i], NULL, thread_func, NULL))
return 1;
for (int i = 0; i < sizeof(threads) / sizeof(*threads); ++i)
if (pthread_join(threads[i], NULL))
return 2;
return 0;
}
请注意,我不能在
thread_func中分配/释放内存 输出是:
Thread id: 7efda7cdd700, local tlb address is: 7efda0000b20 <-- 1st thread
Thread id: 7efda7cdd700, local tlb address is: 7efda0000b20
Thread id: 7efda84de700, local tlb address is: 7efda0000f50 <-- 2nd thread
Thread id: 7efda84de700, local tlb address is: 7efda0000f50
Thread id: 7efda8cdf700, local tlb address is: 7efda0000f70 <-- 3rd thread
Thread id: 7efda8cdf700, local tlb address is: 7efda0000f70
这是一种魅力,但不幸的是,这段代码造成了不可避免的内存泄漏:(
这里func_needs_storage()是一个需要临时缓冲区来处理一些数据的函数,它可能会被多次调用。它使用的内存应该是动态的,并且可能非常大(高达兆字节)并且几乎不能放在堆栈上。我不想在每次调用函数时都分配缓冲区,所以我将指向它的指针存储在线程局部静态变量中,每个线程都是唯一的。
问题是:当线程退出并且**保证**不再使用此内存时,是否可以在 C 中解除分配此线程本地内存缓冲区?也许我应该使用一些pthread API 或者以某种方式声明我的变量而不是__thread?编译器是最新的gcc/clang,操作系统是archlinux/freebsd。
作为 C++ 中的参考示例,我可以将缓冲区包装在 ThreadLocalStorage 类中,并创建析构函数来释放其内部内存。然后,如果一个声明一个static thread_local ThreadLocalStorage,一旦这个线程退出,它的析构函数就会被调用。
【问题讨论】:
-
是否可以更改
func_needs_storage的签名(添加参数)? -
@1201ProgramAlarm 可能,取决于您的具体建议
-
您不能解除分配线程本地存储,但由于每个线程只需要 4 或 8 个字节,您不必担心这一点。线程需要调用 free() 以避免泄漏。
-
它使用的内存应该是动态的,并且可能非常大(高达兆字节)并且几乎不能放在堆栈上。为什么不能 内存放在堆栈上?你有complete control over the size of the stack used for a POSIX thread。
-
@AndrewHenle 说得好,安德鲁,我明天去看看
标签: c multithreading thread-local thread-local-storage