从另一个线程访问主线程的局部变量

Accessing a local variable of the main thread from another thread

以下是 Computer Systems: A Programmer's Perspective 一书中的示例程序,作者在其中说明了共享变量在多线程程序中的用法:

#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;
}

可以看出,两个线程都访问全局变量ptr,它指向调用pthread_exit.

的主线程的局部变量msgs

现在,根据pthread_exit的文档:

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

那么,上面的代码正确吗?

即使主线程调用pthread_exit,从另一个线程访问主线程的局部变量是否合法?

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

没有。一旦主线程通过pthread_exit完成,任何局部变量的生命周期(即自动存储持续时间)结束。来自另一个线程的任何进一步访问都是 未定义的行为

So, is the code above correct?

没有。 msgs 数组是一个局部变量,其生命周期在 pthread_exit 调用后结束。因此,通过 ptr 进行的任何进一步访问都是未定义的。

一般来说,从一个线程访问另一个线程的局部变量是有效的,只要那些对象的生命周期没有结束。这是由 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.

另一件需要注意的事情是,如果您已将 msgs[0]msgs[1] 传递给线程,那将是有效的。因为 msgs[0]msgs[1] 指向的字符串文字的生命周期仅在程序终止时结束(而不仅仅是指向它的线程)。

同样,如果你通过malloc(或它的朋友)或任何具有静态存储持续时间的对象分配并传递给线程函数,它是有效的。

例如

#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);
}

这完全没问题,因为 p 指向一个字符串文字,它甚至在 main returns 之后通过 pthread_exit.

存在

所以这里要注意的重要区别是,在另一个线程中对变量的访问是否未定义取决于所述对象的生命周期,而不仅仅是变量发生的位置待定义。