gpt4 book ai didi

c - pthread_create 后跟 pthread_detach 仍然会导致 Valgrind 中可能丢失错误

转载 作者:太空狗 更新时间:2023-10-29 17:18:45 25 4
gpt4 key购买 nike

Valgrind 告诉我我可能丢失了一些内存时遇到问题:

==23205== 544 bytes in 2 blocks are possibly lost in loss record 156 of 265
==23205== at 0x6022879: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==23205== by 0x540E209: allocate_dtv (in /lib/ld-2.12.1.so)
==23205== by 0x540E91D: _dl_allocate_tls (in /lib/ld-2.12.1.so)
==23205== by 0x623068D: pthread_create@@GLIBC_2.2.5 (in /lib/libpthread-2.12.1.so)
==23205== by 0x758D66: MTPCreateThreadPool (MTP.c:290)
==23205== by 0x405787: main (MServer.c:317)

创建这些线程的代码 (MTPCreateThreadPool) 基本上是获取一个等待 pthread_t 槽 block 的索引,并以此创建一个线程。 TI 成为指向具有线程索引和 pthread_t 的结构的指针。 (简化/ sanitizer ):

for (tindex = 0; tindex < NumThreads; tindex++)
{
int rc;
TI = &TP->ThreadInfo[tindex];
TI->ThreadID = tindex;

rc = pthread_create(&TI->ThreadHandle,NULL,MTPHandleRequestsLoop,TI);
/* check for non-success that I've omitted */
pthread_detach(&TI->ThreadHandle);
}

然后我们有一个 MTPDestroyThreadPool 函数,它循环遍历我们创建的所有线程并取消它们(因为 MTPHandleRequestsLoop 不会退出)。

for (tindex = 0; tindex < NumThreads; tindex++)
{
pthread_cancel(TP->ThreadInfo[tindex].ThreadHandle);
}

我在其他地方(包括关于 SO 的其他问题)读到明确分离线程可以防止这种可能丢失的错误,但显然不是。有什么想法吗?

最佳答案

glibc 的线程实现故意泄漏内存。它将分配给线程上下文的内存缓存起来,以便在下次创建线程时重用。我对没有缓存的实现做了一些基准测试,看起来缓存将 pthread_create 的最佳时间缩短了 50%,但大大减慢了 pthread_join,对于净亏损。当然,如果您关心的是线程创建延迟而不是吞吐量,这仍然是一个(小) yield 。

另请注意,分离线程很难释放其上下文,即使它想这样做。对于可连接线程,调用 pthread_join 的线程可以释放上下文,但分离线程必须能够在释放其上下文和终止自身之间的间隔期间在没有堆栈的情况下运行。这只能通过用纯 asm 编写一小段代码来实现。

想知道在没有类似竞争条件的情况下分离线程的上下文如何返回到缓存? Linux 具有在线程终止时将特定地址(由用户空间线程库注册)的 int 清零的功能。因此线程可以安全地将自己的上下文添加到缓存中,因为在它终止之前,其他线程仍会在该地址看到一个非零值(通常是它的线程 ID)并将其解释为上下文仍在使用中。

关于c - pthread_create 后跟 pthread_detach 仍然会导致 Valgrind 中可能丢失错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4567765/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com