如何解决从另一个线程访问主线程的局部变量
以下是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]
和 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
通过 pthread_exit
返回后仍然存在的字符串文字。
所以这里要注意的重要区别是,对另一个线程中的变量的访问是否未定义取决于所述对象的生命周期,而不仅仅是变量碰巧被定义的位置。
,以下建议的代码:
- 干净地编译
- 执行所需的功能
- 证明每个线程都在自己的时间内运行,而不是(有必要)按照其创建顺序运行。
- 消除“未知”头文件:
csapp.h
- 包括应用程序所需的头文件
- 显示
main()
的“有效”签名 - 演示如何正确使用
tid
变量/数组 - 演示如何退出线程函数
- 演示如何让
main()
等待线程功能完成 - 使用
size_t
,因此没有隐式转换 - 演示如何打印
size_t
变量 - 展示了
pthread_*
函数的一些错误处理
现在,建议的代码:
//#include "csapp.h"
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define N 2
void *thread(void *vargp);
char **ptr; /* Global variable */
int main( void )
{
pthread_t tid[N];
char *msgs[N] = {
"Hello from foo","Hello from bar"
};
ptr = msgs;
for ( size_t i = 0; i < N; i++)
{
if( pthread_create(&tid[i],thread,(void *)i) != 0)
{
fprintf( stderr,"pthread_create failed\n" );
exit( EXIT_FAILURE );
}
}
for( size_t i= 0; i<N; i++ )
{
if( pthread_join( tid[i],NULL ) != 0 )
{
fprintf( stderr,"pthread_join failed\n" );
exit( EXIT_FAILURE );
}
}
}
void *thread(void *vargp)
{
size_t myid = ( size_t )vargp;
static int cnt = 0;
printf("[%zu]: %s (cnt=%d)\n",myid,ptr[myid],++cnt);
pthread_exit( NULL );
}
典型的代码运行结果为:
[0]: Hello from foo (cnt=1)
[1]: Hello from bar (cnt=2)
注意:输出也可以是:
[1]: Hello from bar (cnt=1)
[0]: Hello from foo (cnt=2)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。