Search code examples
clinuxpthreadsposix

Why does a joinable thread terminate before pthread_join?


The documentation for the pthread_join function says:

Failure to join with a thread that is joinable (i.e., one that is not detached), produces a "zombie thread".

As far as I understand this statement, after the thread terminates, it remains a zombie until we call pthred_join. However, I wrote a program and it turned out that the completed joinable thread is completely terminated after return. But how then do we get the thread exit code in pthread_join? Where is the exit code stored?

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>

void *mythread(void *arg)
{
    printf("mythread [%d %d %d]: Hello from mythread!\n", getpid(), getppid(), gettid());
    int *result = malloc(sizeof(int));
     *result = 42;
     return result;
}

int main() {
    pthread_t tid;
    int err;

    printf("main [%d %d %d]: Hello from main!\n", getpid(), getppid(), gettid());

    err = pthread_create(&tid, NULL, mythread, NULL);
    if (err) {
        printf("main: pthread_create() failed: %s\n", strerror(err));
        return -1;
    }

    sleep(1000);

    void *thread_result;

    if (pthread_join(tid, &thread_result) != 0) {
        perror("Thread join failed");
        return 1;
    }
    printf("Thread returned: %d\n", *((int *)thread_result));
    return 0;
}

Launching the program

View process threads

It can be seen that in the process table there is only the main thread.


Solution

  • The thread exit code of a joinable thread that is still not joined is stored in the zombie thread. That's what zombie threads are, more or less: pieces of data that store thread exit codes.

    Under Linux, a zombie thread is not a process (i.e. doesn't have an entry in the process table) so ps will not show it. pthread_exit calls exit (the system call, not the eponymous C library function) so that the process that corresponds to that thread truly terminates. There is no trace of it in the process table. However there is still a zombie thread hanging somewhere.