Accessing a local variable of the main thread from another thread

Viewed 454

The following is an example program from the book Computer Systems: A Programmer's Perspective where the authors illustrate the usage of shared variables in multi-threaded programs:

#include "csapp.h"

#define N 2

void *thread(void *vargp);

char **ptr; /* Global variable */

int main()
{
    int i;
    pthread_t tid;
    char *msgs[N] = {
        "Hello from foo",
        "Hello from bar"
    };

    ptr = msgs;
    for (i = 0; i < N; i++)
        Pthread_create(&tid, NULL, thread, (void *)i);
    Pthread_exit(NULL);
}

void *thread(void *vargp)
{
    int myid = (int)vargp;
    static int cnt = 0;
    printf("[%d]: %s (cnt=%d)\n", myid, ptr[myid], ++cnt);
    return NULL;
}

As can be seen, both threads access the global variable ptr which points to the local variable msgs of the main thread which calls pthread_exit.

Now, according to the documentation of pthread_exit:

After a thread has terminated, the result of access to local (auto) variables of the thread is undefined.

So, is the code above correct?

Is it legal to access a local variable of the main thread from another thread even though the main thread calls pthread_exit?

1 Answers

Is it legal to access a local variable of the main thread from another thread even though the main thread calls pthread_exit?

No. Once the main thread completes via pthread_exit, the lifetime of any local variable (i.e. automatic storage duration) ends. Any further access from another thread is undefined behaviour.

So, is the code above correct?

No. The msgs array is a local variable whose lifetime ends after pthread_exit call. So any further access via ptr is undefined.

In general, it's valid to access local variables of one thread from another thread as long as the lifetime of those objects haven't ended. This is guaranteed by POSIX:

[..] Anything whose address may be determined by a thread, including but not limited to static variables, storage obtained via malloc(), directly addressable storage obtained through implementation-defined functions, and automatic variables, are accessible to all threads in the same process.

Another thing to note is that if you have passed msgs[0] or msgs[1] to the threads, that would be valid. Because msgs[0] and msgs[1] point to string literals whose lifetime ends only when the program terminates (not just the thread which has a pointer to it).

Similarly, it's valid if you have allocated via malloc (or its friends) or any object with static storage duration and passed it to the thread function.

e.g.

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

void *thread_func(void *arg)
{
    char *str = p;
    printf("%s\n", str);
    return NULL;
}

int main(void)
{
    pthread_t tid;
    char *p = "Hello";
    pthread_create(&tid, NULL, thread_func, p);
    pthread_exit(NULL);
}

This is totally fine because p points to a string literal which exists even after main returns via pthread_exit.

So the important distinction to note here is that whether the access to a variable in another thread is undefined depends on the lifetime of the said object, not just where a variable happens to be defined.

Related