多线程编程指南

获取线程特定数据

请使用 pthread_getspecific(3C) 获取调用线程的绑定,并将该绑定存储在 value 指向的位置中。

pthread_getspecific 语法

void	*pthread_getspecific(pthread_key_t key);
#include <pthread.h>



pthread_key_t key;

void *value;



/* key previously created */

value = pthread_getspecific(key); 

pthread_getspecific 返回值

pthread_getspecific 不返回任何错误。

全局和专用线程特定数据的示例

示例 2–2 显示的代码是从多线程程序中摘录出来的。这段代码可以由任意数量的线程执行,但该代码引用了两个全局变量:errnomywindow。这些全局值实际上应当是对每个线程专用项的引用。


示例 2–2 线程特定数据-全局但专用

body() {

    ...



    while (write(fd, buffer, size) == -1) {

        if (errno != EINTR) {

            fprintf(mywindow, "%s\n", strerror(errno));

            exit(1);

        }

    }



    ...



}

errno 引用应该从线程所调用的例程获取系统错误,而从其他线程所调用的例程获取系统错误。因此,线程不同,引用 errno 所指向的存储位置也不同。

mywindow 变量指向一个 stdio (标准 IO)流,作为线程专属的流窗口。因此,与 errno 一样,线程不同,引用 mywindow 所指向的存储位置也不同。最终,这个引用指向不同的流窗口。唯一的区别在于系统负责处理 errno,而程序员必须处理对 mywindow 的引用。

下一个示例说明对 mywindow 的引用如何工作。预处理程序会将对 mywindow 的引用转换为对 _mywindow() 过程的调用。

此例程随后调用 pthread_getspecific()pthread_getspecific() 接收 mywindow_key 全局变量作为输入参数,以输出参数 win 返回该线程的窗口。


示例 2–3 将全局引用转化为专用引用

thread_key_t mywin_key;



FILE *_mywindow(void) {

    FILE *win;



    win = pthread_getspecific(mywin_key);

    return(win);

}



#define mywindow _mywindow()



void routine_uses_win( FILE *win) {

    ...

}



void thread_start(...) {

    ...

    make_mywin();

    ...

    routine_uses_win( mywindow )

    ...

}

mywin_key 变量标识一类变量,对于该类变量,每个线程都有其各自的专用副本。这些变量是线程特定数据。每个线程都调用 make_mywin() 以初始化其时限并安排其 mywindow 实例以引用线程特定数据。

调用此例程之后,此线程可以安全地引用 mywindow,调用 _mywindow() 之后,此线程将获得对其专用时限的引用。引用 mywindow 类似于直接引用线程专用数据。

示例 2–4 说明如何设置引用。


示例 2–4 初始化线程特定数据

void make_mywindow(void) {

    FILE **win;

    static pthread_once_t mykeycreated = PTHREAD_ONCE_INIT;



    pthread_once(&mykeycreated, mykeycreate);



    win = malloc(sizeof(*win));

    create_window(win, ...);



    pthread_setspecific(mywindow_key, win);

}



void mykeycreate(void) {

    pthread_key_create(&mywindow_key, free_key);

}



void free_key(void *win) {

    free(win);

}

首先,得到一个唯一的键值,mywin_key。此键用于标识线程特定数据类。第一个调用 make_mywin() 的线程最终会调用 pthread_key_create(),该函数将唯一的 key 赋给其第一个参数。第二个参数是 destructor 函数,用于在线程终止后将该线程的特定于该线程的数据项实例解除分配。

接下来为调用方的线程特定数据项的实例分配存储空间。获取已分配的存储空间,调用 create_window(),以便为该线程设置时限。win 指向为该时限分配的存储空间。最后,调用 pthread_setspecific(),将 win 与该键关联。

以后,每当线程调用 pthread_getspecific() 以传递全局 key,线程都会获得它在前一次调用 pthread_setspecific() 时设置的与该键关联的值)。

线程终止时,会调用在 pthread_key_create() 中设置的 destructor 函数。每个 destructor 函数仅在终止线程通过调用 pthread_setspecific()key 赋值之后才会被调用。