In the CSAPP book Section 12.3, They said..
The thread terminates explicitly by calling the pthread_exit function. If the main thread calls pthread_exit, it waits for all other peer threads to terminate and then terminates main thread and the entire process with a return value of thread_return.
However in the man page of pthread_exit : https://man7.org/linux/man-pages/man3/pthread_exit.3.html
Performing a return from the start function of any thread other than the main thread results in an implicit call to pthread_exit(), using the function's return value as the thread's exit status.
To allow other threads to continue execution, the main thread should terminate by calling pthread_exit() rather than exit(3).
Two descriptions about pthread_exit are different. First one said main thread will wait for peer but not on second.
Therefore I write a code to ensure correct property.
(I borrow some code lines from When the main thread exits, do other threads also exit?)
(Thanks to https://stackoverflow.com/users/959183/laifjei)
Since pthread_cancel is called before pthread_exit, main thread cancel t1 thread successfully and the result is like,,
However, when I modify a code as '42 line -> add //' and '44 line -> delete //', main thread cannot cancel t1 since it was already terminated. Therefore the following result is looks like,,
Finally, I conclude that man page's property is correct. Am I right?
Why does CSAPP book said that "it waits for all other peer threads to terminate"?
Two descriptions about pthread_exit are different. First one said main thread will wait for peer but not on second.
Not very different, and not in a way that you can easily distinguish by most means.
In particular, regardless of whether the main thread terminates immediately or waits for other threads to terminate before doing so, the pthread_exit()
function is like the exit()
function in that it does not return. Observing that statements inserted into your test program between the pthread_exit()
call and the end of main
are not executed does yield any information that helps you determine the relative sequence of thread terminations.
For that reason, the question is also largely moot. Although there indeed are ways in which the difference can be observed, it is rarely significant.
Nevertheless, here's a better example:
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
pthread_t main_thread;
void *wait_for_main(void *unused) {
void *main_rval;
// Wait for the main thread to terminate
if ((errno = pthread_join(main_thread, &main_rval)) != 0) {
perror("pthread_join");
} else {
fputs("The main thread was successfully joined\n", stderr);
}
fflush(stderr);
return NULL;
}
int main(void) {
pthread_t child_thread;
main_thread = pthread_self();
if ((errno = pthread_create(&child_thread, NULL, wait_for_main, NULL)) != 0) {
perror("pthread_create");
} else {
fputs("The child thread was successfully started\n", stderr);
}
pthread_exit(NULL);
}
That program runs successfully, printing ...
The child thread was successfully started
The main thread was successfully joined
This shows that the main thread indeed terminated (because it was successfully joined), and that the other thread continued to run afterward (because it wrote its message to stderr
).
You go on to ask ...
Why does CSAPP book said that "it waits for all other peer threads to terminate"?
... but no one other than Bryant, O'Hallaron, or one of their editors could definitively answer the question (and maybe not all -- or any -- of those). Here are some possibilities:
Or my actual best guess:
pthread_exit()
. That is the book is talking about pthread implementation details, not documented, observable pthread semantics.