-1

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)

enter image description here

Since pthread_cancel is called before pthread_exit, main thread cancel t1 thread successfully and the result is like,,

enter image description here

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,,

sorry for some mistakes like wq

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"?

alsrbok
  • 15
  • 6
  • In my example and man page, main thread never waits for all other peer threads. – alsrbok May 22 '21 at 07:51
  • How does your example show what you claim it does? I see you terminating the program with `ctrl-C`. – EOF May 22 '21 at 07:56
  • That's beacuse test 1 and test 2 never shut down spontaneously. They are in the infinite while loop and only code *thread_cancel* in main thread terminate t1. – alsrbok May 22 '21 at 07:59
  • Since different location of *thread_cancel* change the result, I can find out that only main thread is terminated by *pthread_exit*. – alsrbok May 22 '21 at 08:00
  • My point is "*pthread_exit* function is wait for all other peer threads terminate or not" and my example clearly shows that it never wait for peer thread and shut down only itself. Therefore thread 2 always survive in infinite loop. – alsrbok May 22 '21 at 08:02
  • None of what you're saying makes any sense. The main thread *is* **clearly** waiting for all other threads to terminate when it calls `pthread_exit()`, just like **both** of the pieces of documentation say it will. – EOF May 22 '21 at 08:25
  • Then how can you explain the second situation? When the *pthread_cancel* locate after *pthread_exit*, main thread is failed to cancel thread t1. Isn't it shows that main thread is already terminated by *pthread_exit* and never wait for other threads to terminate? – alsrbok May 22 '21 at 08:33
  • All of your comments never explain the reason. You just repeat the definition ,saying I am wrong. – alsrbok May 22 '21 at 08:34
  • When `pthread_cancel()` is after `pthread_exit()`, the main thread does not "fail to cancel thread t1", the main thread is *already exited*, so it *cannot* and *must not* execute the `pthread_cancel()`. However, in both cases, after the main thread exits, the program *continues executing* until all other threads exit too. *That* is what is meant by "it waits for all other peer threads..." and "To allow other threads to continue execution..." in your documentation. Compare & contrast with the behavior if you replace `pthread_exit();` in `main()` with `exit();` or `return 0;`. – EOF May 22 '21 at 08:41
  • In man page's description, they said *the main thread should terminate by calling pthread_exit() rather than exit(3).* It means that **main thread is already terminated** by *pthread_exit()*. However in the csapp book, it said * it waits for all other peer threads to terminate **and then terminates main thread** *. It's different. – alsrbok May 22 '21 at 09:50
  • "fail to cancel thread t1" means "do not execute cacncel". I used "fail" because I was comparing two situation. – alsrbok May 22 '21 at 09:52
  • Calling `pthead_exit()` causes the calling thread to terminate. Being terminated means that none of the code written after `pthread_exit()` will be executed. However, it does not mean that the thread instantly stops existing. It still performs its registered cleanup handlers (see `pthread_cleanup_push()`, and (in the case of the main thread), waiting for all other threads to terminate. – EOF May 22 '21 at 10:06
  • Finally I got it. Difference between "terminated" and "existing" confuse me. Thanks for your effort. It helps me a lot. – alsrbok May 22 '21 at 10:30

1 Answers1

1

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:

  • The book is just wrong. It happens.
  • The book is unclear or imprecise, in that it means the "it" that waits to be the overall program, the operating system, or some other variation on "something other than the main thread".

Or my actual best guess:

  • The book is is describing behavior from an operating system perspective, whereas the Pthreads documentation is describing it from a C-language perspective. It may well be that the OS thread that is the process's main one indeed is the thing that waits for others to terminate, but its C-language semantics within the running program terminate with the pthread_exit(). That is the book is talking about pthread implementation details, not documented, observable pthread semantics.
John Bollinger
  • 160,171
  • 8
  • 81
  • 157