首页 > 解决方案 > 从另一个线程访问主线程的局部变量

问题描述

以下是《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指向msgs调用pthread_exit.

现在,根据pthread_exit的文档:

线程终止后,访问线程的本地(自动)变量的结果是未定义的。

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

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

标签: cmultithreadingpthreadsposix

解决方案


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

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

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

不,该msgs数组是一个局部变量,其生命周期在pthread_exit调用后结束。所以任何进一步的访问ptr都是未定义的。

一般来说,只要这些对象的生命周期没有结束,从另一个线程访问一个线程的局部变量是有效的。这是由POSIX保证的:

[..] 任何可以由线程确定地址的东西,包括但不限于静态变量、通过 malloc() 获得的存储、通过实现定义的函数获得的直接可寻址存储以及自动变量,都可以被线程中的所有线程访问。相同的过程。

另一件需要注意的是,如果你已经通过了线程msgs[0]msgs[1]那将是有效的。因为msgs[0]andmsgs[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通过pthread_exit.

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


推荐阅读