我正在尝试在不全局变量的两个线程之间共享一个结构。变量本身在main函数的堆栈上实例化,然后在两个线程启动时将其指针作为参数传递给两个线程。
我发现当我更改该结构成员的值时,其他pthread中的永远不会反映 。有没有办法在两个线程之间共享一个非全局变量(例如一个整数),这样在一个线程中对该变量所做的更改会出现在另一个线程中?
这就是因为我想避免为代码可维护性添加全局变量。
答案 0 :(得分:8)
请记住,线程获得自己的堆栈 - 所以如果你传入一个整数并且函数超出范围,那么你指的是现在存在完全不同的内存。
void foo(void)
{
pthread_t t1, t2;
struct foo common_value;
if (pthread_create(&t1, NULL, a, &common_value) != 0)
{
return -1;
}
if (pthread_create(&t2, NULL, b, &common_value) != 0)
{
return -1;
}
// upon exiting this function, common_value is no longer what you think it is!
}
答案 1 :(得分:2)
我没有假装优雅,但这似乎适用于MacOS X 10.5.8。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static void *writer(void *arg)
{
int * volatile i = arg;
for (*i = 1; *i < 10; (*i)++)
{
printf("writer(): pseudo_global = %d\n", *i);
fflush(stdout);
sleep(1);
}
printf("writer(): pseudo_global = %d (exiting)\n", *i);
fflush(stdout);
return(0);
}
static void *reader(void *arg)
{
int * volatile i = arg;
while (*i < 10)
{
printf("reader(): pseudo_global = %d\n", *i);
fflush(stdout);
sleep(1);
}
printf("reader(): pseudo_global = %d (exiting)\n", *i);
fflush(stdout);
exit(0);
}
int main(void)
{
volatile int pseudo_global = 0;
pthread_t t1;
pthread_t t2;
if (pthread_create(&t1, 0, writer, &pseudo_global) != 0)
{
perror("pthread_create() for thread 1");
exit(1);
}
if (pthread_create(&t2, 0, reader, &pseudo_global) != 0)
{
perror("pthread_create() for thread 1");
exit(1);
}
while (pseudo_global < 10)
{
printf("main(): pseudo_global = %d\n", pseudo_global);
fflush(stdout);
sleep(1);
}
printf("main(): pseudo_global = %d (exiting)\n", pseudo_global);
fflush(stdout);
return(0);
}
请注意,我将'volatile'限定符放入代码中以“确保”,但除了在调用pthread_create()
时引发有关丢弃限定词的警告之外,它没有产生任何显着差异。我也没有任何volatile
限定符运行代码而没有问题。
我认为,这段代码证明,在至少一个POSIX线程实现中,您确实可以在线程运行时尚未退出的函数堆栈上共享局部变量。
我愿意相信我应该更加小心线程终止,并且应该确保main()
不会在不使用pthread_join()
的情况下退出,以确保线程首先退出。
示例输出:
$ make ptex
gcc -O ptex.c -o ptex
ptex.c: In function ‘main’:
ptex.c:40: warning: passing argument 4 of ‘pthread_create’ discards qualifiers from pointer target type
ptex.c:45: warning: passing argument 4 of ‘pthread_create’ discards qualifiers from pointer target type
$ ./ptex
writer(): pseudo_global = 1
main(): pseudo_global = 0
reader(): pseudo_global = 1
writer(): pseudo_global = 2
main(): pseudo_global = 2
reader(): pseudo_global = 2
writer(): pseudo_global = 3
main(): pseudo_global = 3
reader(): pseudo_global = 3
writer(): pseudo_global = 4
main(): pseudo_global = 4
reader(): pseudo_global = 4
writer(): pseudo_global = 5
reader(): pseudo_global = 5
main(): pseudo_global = 5
writer(): pseudo_global = 6
reader(): pseudo_global = 6
main(): pseudo_global = 6
writer(): pseudo_global = 7
reader(): pseudo_global = 7
main(): pseudo_global = 7
writer(): pseudo_global = 8
reader(): pseudo_global = 8
main(): pseudo_global = 8
writer(): pseudo_global = 9
reader(): pseudo_global = 9
main(): pseudo_global = 9
writer(): pseudo_global = 10 (exiting)
reader(): pseudo_global = 10 (exiting)
main(): pseudo_global = 10 (exiting)
$
答案 2 :(得分:1)
你做的是正确的,但你的经验表明你做错了。请尝试将其移动到全局变量中,看看您是否继续体验非共享。
检查完毕后,请发布一些简单的示例代码,说明其他人可以测试的问题。
答案 3 :(得分:1)
在我看来,共享一个堆栈变量比拥有一个全局变量更糟糕。至少我会在堆上分配一些内存以在线程之间共享。如果内存在程序的生命周期中存在,你甚至不必担心释放它,并且主线程可以立即返回。使用堆栈变量,您必须确保不会过早弹出变量所在的堆栈帧。
话虽如此,我认为使用全局实际上是更好的解决方案。将全局放在一个单独的文件中并将其声明为 static ,以使其仅对文件是全局的。然后,只将您的线程函数放在该文件中,这样只有它们才能访问该变量。我更喜欢这个,因为它明确表示内存是由线程共享的。 pthread_create的参数实际上是指特定于线程的上下文,从查看线程函数来看,并不一定要清楚所有线程都传递相同的指针。