Is it OK to call pthread_exit from main?

pthread_exit geeksforgeeks
pthread_exit implementation
pthread_join
pthread_exit return value example
pthread_join example
pthread_exit crash
pthread_exit exit
pthread terminate

When I call pthread_exit from main, the program never gets to terminate. I expected the program to finish, since I was exiting the program's only thread, but it doesn't work. It seems hung.

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int main(int argc, char *argv[])
{
    printf("-one-\n");

    pthread_exit(NULL);

    printf("-two-\n");
}

Process Explorer shows that the (only) thread is in Wait:DelayExecution state.

According to pthread_exit documentation:

The process shall exit with an exit status of 0 after the last thread has been terminated. The behavior shall be as if the implementation called exit() with a zero argument at thread termination time.

I'm using Dev-C++ v4.9.9.2 and pthreads-win32 v2.8.0.0 (linking against libpthreadGC2.a).

The library seems to be OK (for example, calling pthread_self or pthread_create from main works fine).

Is there any reason for what I'm not supposed to call pthread_exit from main?

Well its definately legal in the linux implementation of pthreads, see the notes section in pthreads_exit. It states

To allow other threads to continue execution, the main thread should terminate by calling pthread_exit() rather than exit(3).

Further, a look at the source code here (torwads the end) shows that it roughly translates to _endthread or _endthreadex. The documentation here for those makes no mention of not calling it in the initial thread.

How to close a thread from within?, () function terminates the calling thread and makes the value value_ptr available to any successful join with the terminating thread. Any cancellation cleanup handlers that have been pushed and not yet popped are popped in the reverse order that they were pushed and then executed. 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) .

This completely legal and intended behavior. The whole process only ends when either all threads terminate or exit is called explicitly or implicitly.

A normal return from main is equivalent to a call to exit. If you end main with pthread_exit your are saying explicitly that you want the other threads to continue.

When the main thread exits, do other threads also exit?, When using pthread for multithreading, most threads call pthread_exit() implicitly on return from the thread start routine. Besides, pthread_exit()  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).

It's fine to use pthread_exit in main. When pthread_exit is used, the main thread will stop executing and will remain in zombie(defunct) status until all other threads exit.

If you are using pthread_exit in main thread, cannot get return status of other threads and cannot do clean-up for other threads (could be done using pthread_join(3)). Also, it's better to detach threads(pthread_detach(3)) so that thread resources are automatically released on thread termination. The shared resources will not be released until all threads exit.

Its ok to use when not allocating resources in the main thread, clean-up is not needed. Below code shows using pthread_exit in the main thread. The second printf in main is not printed as main thread exits after calling pthread_exit. Ps output shows the defunct main thread.

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>

void *functionC(void *);

int main()
{
        int rc;
        pthread_t th;

        if(rc = pthread_create(&th, NULL, &functionC, NULL))
        {
                printf("Thread creation failed, return code %d, errno %d", rc,                 errno);
        }

        printf("Main thread %lu: Sleeping for 20 seconds\n", pthread_self());
        fflush(stdout);
        sleep(20);
        pthread_exit(NULL);
        printf("Main thread %lu: This will not be printed as we already called         pthread_exit\n", pthread_self());
        exit(0);
}

void *functionC(void *)
{
        printf("Thread %lu: Sleeping for 20 second\n", pthread_self());
        sleep(20);
        printf("Thread %lu: Came out of first and sleeping again\n", pthread_self());
        sleep(20);
        printf("CThread %lu: Came out of second sleep\n", pthread_self());
}

Output of the above code:

Main thread 140166909204288: Sleeping for 20 seconds
Thread 140166900684544: Sleeping for 20 second
Thread 140166900684544: Came out of first and sleeping again
CThread 140166900684544: Came out of second sleep

ps output:

root@xxxx-VirtualBox:~/pthread_tst# ps -elfT |grep a.out
0 S root      9530  9530  9496  0  80   0 -  3722 hrtime 17:31 pts/1    00:00:00 ./a.out
1 S root      9530  9531  9496  0  80   0 -  3722 hrtime 17:31 pts/1    00:00:00 ./a.out
0 S root      9537  9537  2182  0  80   0 -  5384 pipe_w 17:31 pts/0    00:00:00 grep --color=auto a.out

root@xxxx-VirtualBox:~/pthread_tst# ps -elfT |grep a.out
0 Z root      9530  9530  9496  0  80   0 -     0 -      17:31 pts/1    00:00:00 [a.out] <defunct>
1 S root      9530  9531  9496  0  80   0 -  4258 hrtime 17:31 pts/1    00:00:00 ./a.out
0 S root      9539  9539  2182  0  80   0 -  5384 pipe_w 17:31 pts/0    00:00:00 grep     --color=auto a.out`

Please check blog Tech Easy for more information on threads.

pthread_exit, The pthread_exit() function terminates the calling thread and returns a value via retval that (if │pthread_exit() │ Thread safety │ MT-Safe any thread other than the main thread results in an implicit call to pthread_exit(),  pthread_exit() is for threads what exit() is for the main program. Can you always terminate the main program using return? I guess not. This is why exit() and pthread_exit() exist. Returning from the main function of the thread performs an implicit call to pthread_exit(). The function is called no matter how you terminate your thread.

When testing on Linux (CentOS Linux release 7.2.1511 (Core)) I found that indeed the main program waits for "child" threads to continue. Also I was not able to pass out a return code from main, although it can be specified as argument for pthread_exit(), as Raul said above it always returns with exit code 0:

retval=3;
pthread_exit(&retval);

We also observed an error message when using Clang compiler (version 3.4.2) and sanitizer options:

==5811==ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x7f4c090321d0 in thread T0
#0 0x7f4c08be3e29 in __interceptor_free (/home/karstenburger/tests/libc/pthread_exit_in_main/a+0x65e29)
#1 0x7f4c08333358 in free_key_mem (/lib64/libdl.so.2+0x1358)
#2 0x7f4c08745bc1 in __nptl_deallocate_tsd (/lib64/libpthread.so.0+0x7bc1)
#3 0x7f4c07771b38 in __libc_start_main (/lib64/libc.so.6+0x21b38)
#4 0x7f4c08bfa08c in _start (/home/karstenburger/tests/libc/pthread_exit_in_main/a+0x7c08c)

AddressSanitizer can not describe address in more detail (wild memory access suspected).
SUMMARY: AddressSanitizer: bad-free ??:0 __interceptor_free
==5811==ABORTING

Terminating threads, When I call pthread_exit from main, the program never gets to terminate. I expected the program to finish, since I was exiting the program's only thread, but it  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) .

Be careful to pthread_exit() in main() – Bo's Blog, The pthread_exit() function shall terminate the calling thread and make the call to pthread_exit() is made when a thread other than the thread in which main()  Local C++ objects like std::vector or std::string do this, and their destructors probably won't be run if you call pthread_exit, but would be cleaned up if you just return. My preference is to avoid low-level APIs such as pthread_exit , and always just return from the thread function, where possible.

pthread_exit(3) - Linux manual page - Michael Kerrisk, Signal Safe: No. The pthread_exit() function terminates the calling thread, making its exit status available to any waiting threads. makes the compiler smile */ } int main(int argc, char **argv) { pthread_t thread; int rc=0; void *status; printf("Enter  If you're OK using non-ISO C++ APIs then if main calls pthread_exit instead of returning or calling exit then that will cause the process to wait for detached threads to finish, and then call exit after the last one finishes. – Jonathan Wakely Apr 27 '18 at 11:51 2

Is it OK to call pthread_exit from main?, POSIX.1-2001. Notes. Performing a return from the start function of any thread other than the main thread results in an implicit call to pthread_exit()  The pthread_exit() function terminates the calling thread, making its exit status available to any waiting threads. Normally, a thread terminates by returning from the start routine that was specified in the pthread_create() call which started it.

Comments
  • Why don't you return 0; instead of pthread_exit(NULL);?
  • I know I could return or exit. I just want to know if it's legal to terminate the main thread by calling pthread_exit.
  • Returning from main() is very different to running pthread_exit(). The latter will let the rest of alive threads to finish and then exit with return value 0. The former will terminate everything immediately.
  • Then I guess it should be legal in the win32 implementation (sourceware.org/pthreads-win32/bugs.html) too. I've been looking for a known bug that explains this behavior, but I couldn't find it. In my opinion, either this is a buggy behavior or there's an actual reason I am not supposed to call pthread_exit on pthreads_win32. Can anybody confirm any of these hypothesis?
  • @matasierra: I've added some more detail to the answer aboce. Also, what is main actually executing?
  • The first printf is actually printed out, but the second one is not (as expected). The problem is that the program will not terminate. It simply gets kind of frozen.
  • I finally found the problem. I think it was some kind of malware on my operating system. I've just cleaned it up with an antispyware tool and now it works as expected. Oh, my... I feel really stupid. @torak I'm going to accept your answer. Thanks for your help!
  • Did you use a local variable for retval, so its address becomes invalid?