pthreads只能共享全球资源吗?

时间:2009-09-14 07:30:26

标签: multithreading pthreads

我正在尝试在全局变量的两个线程之间共享一个结构。变量本身在main函数的堆栈上实例化,然后在两个线程启动时将其指针作为参数传递给两个线程。

我发现当我更改该结构成员的值时,其他pthread中的永远不会反映 。有没有办法在两个线程之间共享一个非全局变量(例如一个整数),这样在一个线程中对该变量所做的更改会出现在另一个线程中?

这就是因为我想避免为代码可维护性添加全局变量。

4 个答案:

答案 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的参数实际上是指特定于线程的上下文,从查看线程函数来看,并不一定要清楚所有线程都传递相同的指针。