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?

Community
  • 1
  • 1
Witiko
  • 3,167
  • 3
  • 25
  • 43
  • 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. – antiduh Jan 02 '14 at 22:51
  • 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.) – Kerrek SB Jan 02 '14 at 22:53
  • @antiduh: How do you kindly signal a thread in progress that it should quit? – Witiko Jan 02 '14 at 22:58
  • 1
    Use a flag that the thread pays attention to. – antiduh Jan 02 '14 at 23:29
  • 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. – Sam Protsenko Nov 01 '15 at 15:19

1 Answers1

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.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177