js7222
js7222

Reputation: 41

How is parent thread notified when child thread exits

Can someone help me understand what wakes up the main thread after the child thread has exited? My understanding is that join calls futex_wait, causing the main thread to wait until the child thread has finished. Presumably there is a call to futex_wake to allow the master thread to resume but after running strace on both threads, I can't see where the syscall to wake up the parent thread is.

#include <iostream>
#include <thread>
#include <string>

void hello()
{
    std::cout <<"Hello Concurrent World" << std::endl;
}

int main ()
{
    std::thread t(hello);
    t.join();

    std::cout << "finished" << std::endl;
}

strace from parent thread

19:37:06.206727 brk(NULL)               = 0x1380000
19:37:06.206804 brk(0x13b2000)          = 0x13b2000
19:37:06.206968 futex(0x7fcf7953005c, FUTEX_WAKE_PRIVATE, 2147483647) = 0
19:37:06.207331 futex(0x7fcf79530068, FUTEX_WAKE_PRIVATE, 2147483647) = 0
19:37:06.207577 mmap(NULL, 8392704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7fcf780ba000
19:37:06.207726 mprotect(0x7fcf780ba000, 4096, PROT_NONE) = 0
19:37:06.207863 clone(child_stack=0x7fcf788b9fb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7fcf788ba9d0, tls=0x7fcf788ba700, child_tidptr=0x7fcf788ba9d0) = 10204
19:37:06.208005 futex(0x7fcf788ba9d0, FUTEX_WAIT, 10204, NULL) = 0
19:37:06.209781 write(1, "finished\n", 9) = 9
19:37:06.210021 exit_group(0)           = ?
19:37:06.210394 +++ exited with 0 +++

strace from child thread

19:07:09.837174 set_robust_list(0x7f123adba9e0, 24) = 0
19:07:09.837411 fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
19:07:09.837508 mmap(NULL, 134217728, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0) = 0x7f12325ba000
19:07:09.837601 munmap(0x7f12325ba000, 27549696) = 0
19:07:09.837693 munmap(0x7f1238000000, 39559168) = 0
19:07:09.837818 mprotect(0x7f1234000000, 139264, PROT_READ|PROT_WRITE) = 0
19:07:09.837947 write(1, "Hello Concurrent World\n", 23) = 23
19:07:09.838082 madvise(0x7f123a5ba000, 8368128, MADV_DONTNEED) = 0
19:07:09.838164 exit(0)                 = ?
19:07:09.838285 +++ exited with 0 +++

Currently compiled using Ubuntu 16.10, clang version 3.8.1-12, kernel 4.8.0-34-generic

Upvotes: 2

Views: 689

Answers (1)

rustyx
rustyx

Reputation: 85541

This call: set_robust_list(0x7f123adba9e0, 24) = 0 sets a robust futex, which is automatically resumed on thread exit. So no syscall is needed to wake the futex. The kernel will wake the futex on thread exit (even if the thread is killed).

Here's a trace fragment from Debian stretch showing that the fuxes resumes "by itself":

[pid 21604] 20:38:49.614788 futex(0x7f0349dbc9d0, FUTEX_WAIT, 21605, NULL <unfinished ...>
[pid 21605] 20:38:49.614851 set_robust_list(0x7f0349dbc9e0, 24) = 0
[pid 21605] 20:38:49.614948 nanosleep({tv_sec=0, tv_nsec=100000000}, NULL) = 0
[pid 21605] 20:38:49.715377 madvise(0x7f03495bc000, 8368128, MADV_DONTNEED) = 0
[pid 21605] 20:38:49.715554 exit(0)     = ?
[pid 21604] 20:38:49.715674 <... futex resumed> ) = 0
[pid 21605] 20:38:49.715701 +++ exited with 0 +++

Upvotes: 2

Related Questions