c - 从另一个线程访问主线程的局部变量
问题描述
以下是《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
?
解决方案
即使主线程调用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
.
所以这里要注意的重要区别是,对另一个线程中变量的访问是否未定义取决于所述对象的生命周期,而不仅仅是变量恰好被定义的位置。
推荐阅读
- c++ - 错误:未定义对“WinMain@16”的引用
- javascript - 使用js自动调整网格列的大小
- facebook-graph-api - pictame 和 graphixto 如何获取所有 instagram 配置文件的详细信息,因为 instagram 提供的 API 不支持这一点?
- javascript - 如何从服务器端创建可重定向的条带支付网址?
- java - 当常量字符串不在池中时是否正确?
- apache-kafka - 对生产者/经纪人拥有大量消费者的影响
- javascript - 如何修复“在'...附近解析时 JSON 输入意外结束”,“mocha”:“^3.2.0”,“s'”
- json - 如何将我的数据从 wordpress 表单提交保存到 json 文件
- go - Pubsub.pull 请求无法正常工作 - 去吧
- mongodb - 为什么在字段上使用聚合函数 $avg 时 MongoDB 返回 null