A detached pthread causes memory leaks
Asked Answered
R

1

8

There is a known memory leak, when terminating a process with running undetached pthreads. However, detaching the thread doesn't seem to be a solution. Consider the following minimal example:

#include <pthread.h>
#include <stdio.h>

static void* thread(void* _) {
  for(;;); return NULL;
}

int main(void) {
  pthread_attr_t attr; 
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  pthread_t tid; pthread_create(&tid, &attr, thread, NULL);
  pthread_attr_destroy(&attr);
  return 0;
}

A detached thread with an infinite loop is created and the process is immediately terminated. According to pthread_detach(3), the resources of the thread should be automatically released back to the system once the entire process is terminated. That, however, clearly isn't what's happening:

gcc -pthread c.c
valgrind --leak-check=full a.out

==9341== Command: a.out
==9341==
==9341==
==9341== HEAP SUMMARY:
==9341==     in use at exit: 272 bytes in 1 blocks
==9341==   total heap usage: 1 allocs, 0 frees, 272 bytes allocated
==9341==
==9341== 272 bytes in 1 blocks are possibly lost in loss record 1 of 1
==9341==    at 0x4C2ABB4: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9341==    by 0x4012598: _dl_allocate_tls (dl-tls.c:296)
==9341==    by 0x4E3C7B5: pthread_create@@GLIBC_2.2.5 (allocatestack.c:579)
==9341==    by 0x400825: main (in /home/witiko/a.out)
==9341==
==9341== LEAK SUMMARY:
==9341==    definitely lost: 0 bytes in 0 blocks
==9341==    indirectly lost: 0 bytes in 0 blocks
==9341==      possibly lost: 272 bytes in 1 blocks
==9341==    still reachable: 0 bytes in 0 blocks
==9341==         suppressed: 0 bytes in 0 blocks

Should I be concerned? In the actual program I have several blocking threads, so, much like in the minimal example, I can't really pthread_join() with them. Should I be calling pthread_cancel() instead of exit()ing directly?

Repeated answered 2/1, 2014 at 22:46 Comment(5)
You should use some sort of 'kind' signaling mechanism to tell your threads to quit, then wait for them to quit. pthread_cancel() is a 'rude' way to stop a thread, and either may do nothing (the cancel can't be performed due to the current state of the thread) or may corrupt your program state.Vamp
I don't think "resources begin released to the system" means what you think, and there's no easy way to measure that from userspace. (Inspecting /proc/* comes to mind.)Misericord
@antiduh: How do you kindly signal a thread in progress that it should quit?Repeated
Use a flag that the thread pays attention to.Vamp
Actually it just valgrind is thinking that there is a memory leak, where there may not be any. The only way I managed to overcome this annoying warning is to make my pthread joinable, and when it comes to exit (in my case it's Ctrl-C) -- I'm setting some "stop" flag (of volatile sig_atomic_t type) and doing pthread_join() in main thread. pthread function is checking this flag in infinite loop constantly, and when it's set -- pthread breaks from infinite loop and returns from thread function. Once it's done -- pthread_join() returns in main loop and I don't have warning from valgrind.Cheapskate
D
12

Returning from main is equivalent to an exit of the whole process, so this is in effect quite a rude way to terminate your detached thread. Your thread simply hasn't terminated when the main function ends, it only does so later when the exit mechanism forces it. So valgrind is missing the release of the resources of the thread.

The fact that valgrind tells you that there is leaking memory shouldn't worry you by itself, but the fact that your thread is terminated without being able to cleanup and/or finish its task should worry you.

If you want to have your thread continue execution after your main thread ends, you should terminate main by pthread_exit instead of return. Then it is up to your detached thread to decide when to terminate itself. It could decide so, on receiving the necessary information through a state variable that is set atomically or through a mutex/condition mechanism.

Drub answered 2/1, 2014 at 23:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.