What happens to a detached thread inside a forked process when the process dies?
<p>My program forks everytime it has to deal with something, and in every forked process I detach a thread in order to log stats from the forked process: this thread loops to collect data, but it has no actual condition to stop this loop. </p>

<p>I read in <a href="https://stackoverflow.com/questions/19744250/what-happens-to-a-detached-thread-when-main-exits">"What happens to a detached thread when main() exits?"</a> that:</p>

<blockquote>
  <p>As already stated, any thread, whether detached or not, will die with its process on most OSes.</p>
</blockquote>

<p>In my program I provide no stopping condition to the looping thread, since when the process that spawned it will die, the detached thread will die with it. Anyway I felt like I was taking for granted something, so I made the following code to simplify my doubt and exclude the superfluous from my original program.</p>

<p>In this code, every forked process spawns a thread which will print some numbers. </p>

<pre><code>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/wait.h&gt;

#include &lt;thread&gt;

void threadFoo(int id) {
    int i=0;

    // this loop will simulate some stas collecting
    while (i&lt;1000000) {
        printf("[%d]%d \t", id, i);
        ++i;
    }
    printf("\n\n\n");
    return;
}

void forkFoo(int id) {
    std::thread t(threadFoo, id);
    t.detach();
    printf("PID %d detached thread\n", getpid());
    return;
}


int main(void) {

    int i;
    pid_t pid;

    for (i=0; i&lt;3; i++) {
        pid = fork();
        if (pid == 0) {
            forkFoo(i);
            // this sleep will simulate some work
            sleep(1);
            printf("Proc %d about to terminate...even its detached thread?\n");
            _exit(EXIT_SUCCESS);
        }
        else if(pid &gt; 0) {
            // wait for all children to terminate
            wait(NULL);
        }
    }

    printf("main() about to terminate...\n");
}
</code></pre>

<p>The output of the program confirmed that every thread dies with its process</p>

<pre><code>PID 13476 detached thread
[0]0    [0]1    [0]2    [0]3  ...
... [0]48940    [0]48941    Proc 13476 about to terminate...even its detached thread?
PID 13478 detached thread
[1]0    [1]1    [1]2    [1]3 ... [1]42395   [1]42396    Proc 13478 about to terminate...even its detached thread?
PID 13480 detached thread
[2]0    [2]1    [2]2    [2]3 ...
... [2]41664    [2]41665    Proc 13480 about to terminate...even its detached thread?
main() about to terminate...
</code></pre>

<p>Some doubts were raised when I ran this program with <code>valgrind --leak-check=full --show-leak-kinds=all</code>: when every forked process dies, <code>valgrind</code> shows some creepy output (13534 is forked process PID):</p>

<pre><code>==13534== HEAP SUMMARY:
==13534==     in use at exit: 352 bytes in 2 blocks
==13534==   total heap usage: 2 allocs, 0 frees, 352 bytes allocated
==13534== 
==13534== 64 bytes in 1 blocks are still reachable in loss record 1 of 2
==13534==    at 0x4C2B145: operator new(unsigned long) (vg_replace_malloc.c:333)
==13534==    by 0x401DB5: __gnu_cxx::new_allocator&lt;std::_Sp_counted_ptr_inplace&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt;, std::allocator&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt; &gt;, (__gnu_cxx::_Lock_policy)2&gt; &gt;::allocate(unsigned long, void const*) (new_allocator.h:104)
==13534==    by 0x401CE1: std::allocator_traits&lt;std::allocator&lt;std::_Sp_counted_ptr_inplace&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt;, std::allocator&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt; &gt;, (__gnu_cxx::_Lock_policy)2&gt; &gt; &gt;::allocate(std::allocator&lt;std::_Sp_counted_ptr_inplace&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt;, std::allocator&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt; &gt;, (__gnu_cxx::_Lock_policy)2&gt; &gt;&amp;, unsigned long) (alloc_traits.h:351)
==13534==    by 0x401B41: std::__shared_count&lt;(__gnu_cxx::_Lock_policy)2&gt;::__shared_count&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt;, std::allocator&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt; &gt;, std::_Bind_simple&lt;void (*(int))(int)&gt; &gt;(std::_Sp_make_shared_tag, std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt;*, std::allocator&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt; &gt; const&amp;, std::_Bind_simple&lt;void (*(int))(int)&gt;&amp;&amp;) (shared_ptr_base.h:499)
==13534==    by 0x401A8B: std::__shared_ptr&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt;, (__gnu_cxx::_Lock_policy)2&gt;::__shared_ptr&lt;std::allocator&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt; &gt;, std::_Bind_simple&lt;void (*(int))(int)&gt; &gt;(std::_Sp_make_shared_tag, std::allocator&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt; &gt; const&amp;, std::_Bind_simple&lt;void (*(int))(int)&gt;&amp;&amp;) (shared_ptr_base.h:957)
==13534==    by 0x401A35: std::shared_ptr&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt; &gt;::shared_ptr&lt;std::allocator&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt; &gt;, std::_Bind_simple&lt;void (*(int))(int)&gt; &gt;(std::_Sp_make_shared_tag, std::allocator&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt; &gt; const&amp;, std::_Bind_simple&lt;void (*(int))(int)&gt;&amp;&amp;) (shared_ptr.h:316)
==13534==    by 0x4019A9: std::shared_ptr&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt; &gt; std::allocate_shared&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt;, std::allocator&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt; &gt;, std::_Bind_simple&lt;void (*(int))(int)&gt; &gt;(std::allocator&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt; &gt; const&amp;, std::_Bind_simple&lt;void (*(int))(int)&gt;&amp;&amp;) (shared_ptr.h:598)
==13534==    by 0x401847: std::shared_ptr&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt; &gt; std::make_shared&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt;, std::_Bind_simple&lt;void (*(int))(int)&gt; &gt;(std::_Bind_simple&lt;void (*(int))(int)&gt;&amp;&amp;) (shared_ptr.h:614)
==13534==    by 0x401621: std::shared_ptr&lt;std::thread::_Impl&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt; &gt; std::thread::_M_make_routine&lt;std::_Bind_simple&lt;void (*(int))(int)&gt; &gt;(std::_Bind_simple&lt;void (*(int))(int)&gt;&amp;&amp;) (thread:193)
==13534==    by 0x4012AB: std::thread::thread&lt;void (&amp;)(int), int&amp;&gt;(void (&amp;)(int), int&amp;) (thread:135)
==13534==    by 0x400F42: forkFoo(int) (funwiththreadinsidefork.cpp:21)
==13534==    by 0x400FBD: main (funwiththreadinsidefork.cpp:36)
==13534== 
==13534== 288 bytes in 1 blocks are possibly lost in loss record 2 of 2
==13534==    at 0x4C2C9B4: calloc (vg_replace_malloc.c:711)
==13534==    by 0x4012E14: allocate_dtv (dl-tls.c:296)
==13534==    by 0x4012E14: _dl_allocate_tls (dl-tls.c:460)
==13534==    by 0x5359D92: allocate_stack (allocatestack.c:589)
==13534==    by 0x5359D92: pthread_create@@GLIBC_2.2.5 (pthread_create.c:500)
==13534==    by 0x4EE8CAE: std::thread::_M_start_thread(std::shared_ptr&lt;std::thread::_Impl_base&gt;) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==13534==    by 0x4012D1: std::thread::thread&lt;void (&amp;)(int), int&amp;&gt;(void (&amp;)(int), int&amp;) (thread:135)
==13534==    by 0x400F42: forkFoo(int) (funwiththreadinsidefork.cpp:21)
==13534==    by 0x400FBD: main (funwiththreadinsidefork.cpp:36)
==13534== 
==13534== LEAK SUMMARY:
==13534==    definitely lost: 0 bytes in 0 blocks
==13534==    indirectly lost: 0 bytes in 0 blocks
==13534==      possibly lost: 288 bytes in 1 blocks
==13534==    still reachable: 64 bytes in 1 blocks
==13534==         suppressed: 0 bytes in 0 blocks
</code></pre>

<p>Same error (warning?) message for every forked process when it dies.</p>

<p>The final output is about the <code>main()</code> process, PID 13533:</p>

<pre><code>==13533== HEAP SUMMARY:
==13533==     in use at exit: 0 bytes in 0 blocks
==13533==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==13533== 
==13533== All heap blocks were freed -- no leaks are possible
==13533== 
==13533== For counts of detected and suppressed errors, rerun with: -v
==13533== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
</code></pre>

<p>I don't know how to read all this valgrind output and I don't know if my way of handling a detach thread is right: I'm using C++11 and since it is not provided with a garbage collector, I don't know if those <code>possibly lost</code> and <code>still reachable</code> bytes may degrade my program's performance; I fork() quite often (even if every forked process has a lifetime of some seconds) and every forked process spawn a detached thread that logs some stats. When the forked process dies, the thread dies with it, but I don't know if in the long run my program may slow down because of those bytes that valgrind shows me.</p>

<p>In your opinion, is my concern justified? Am I handling rigth the death of detached threads inside forked processes?</p>