线程特定数据

在多线程程序里,我们有可能经常遇到因为函数使用的静态变量无法为不同的线程保存各自的值的问题。有很多办法可以解决,本文就来看一下通过线程特定数据来解决这样的问题。

每个系统支持有限的线程特定数据元素。POSIX要求这个限制不小于128(每个进程)。系统为每个进程维护一个我们称之为key结构的结构数组,如图:

key结构中的标志指示这个数据元素是否正在使用,所有的标志初始化为“不在使用”。当一个线程调用pthread_key_create创建一个新的线程特定数据元素时,系统会返回第一个不在使用的元素。key结构中的析构函数指针,当一个线程终止时,系统将扫描该线程的pkey数组,为每个非空的pkey指针调用相应的析构函数。

除了进程范围的key结构数组外,系统还在进程内维护关于每个线程的多条信息。这些特定于线程的信息我们称之为pthread结构,其部分内容是我们称之为pkey数组的一个128个元素的指针数组。如图:

注意当我们调用pthread_key_create创建一个键时,系统告诉我们这个键。每个线程可以随后为该键存储一个值(指针),而这个指针通常是每个线程通过malloc获得的。

具体的函数如下:

#include <pthread.h>
int pthread_once(pthread_once_t *onceptr, void (*init)(void));
int pthread_key_create(pthread_key_t *keyptr, void (*destructor)(void *value));

void *pthread_getspecific(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, const void *value);
使用用例:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

pthread_key_t rl_key;
pthread_once_t rl_once = PTHREAD_ONCE_INIT;

void destructor(void *value) {
    printf("pthread:%d destructor value(%p)\n", pthread_self(), value);
    free(value);// 线程结束后执行
}

void create_key() {
    pthread_key_create(&rl_key, destructor);// 申请一个key
    printf("pthread:%d create_key %d\n", pthread_self(), rl_key);
}

void *foo(void *param) {
    int i;
    for(i = 0; i < 2; i++) {
    pthread_once(&rl_once, create_key); // 只运行一次create_key

    void *ptr;
    if ( (ptr = pthread_getspecific(rl_key)) == NULL) {// 检查当前线程key域是否有值
        ptr = malloc(10);
        pthread_setspecific(rl_key, ptr);// 设置key的值
        printf("pthread:%d key(%d) value(%p)\n", pthread_self(), rl_key, ptr);
    }
    }
}

int main(void)
{
    pthread_t t[5];
    int i;
    for(i = 0; i < 5; i++) {
        pthread_create(&t[i], NULL, foo, NULL);
    }


    for(i = 0; i < 5; i++) {
        pthread_join(t[i], NULL);
    }

    return 0;
}
pthread_once(&rl_once, create_key)
不管多少个线程只有第一个执行它的线程运行一次被掉函数,保证了分配的rl_key的安全。

if ( (ptr = pthread_getspecific(rl_key)) == NULL) {// 检查当前线程key域是否有值

检查当前线程的pthread结构的key域是否有值

pthread_setspecific(rl_key, ptr);// 设置key的值
设置当前线程的pthread结构的key域的值

void destructor(void *value) {
    printf("pthread:%d destructor value(%p)\n", pthread_self(), value);
    free(value);// 线程结束后执行
}
线程结束后,会自动掉此析构函数,释放分配资源。

上例运行结果如下:

pthread:1691465472 create_key 0
pthread:1691465472 key(0) value(0x7f2b5c0008c0)
pthread:1680975616 key(0) value(0x7f2b540008c0)
pthread:1659995904 key(0) value(0x7f2b440008c0)
pthread:1659995904 destructor value(0x7f2b440008c0)
pthread:1680975616 destructor value(0x7f2b540008c0)
pthread:1691465472 destructor value(0x7f2b5c0008c0)
pthread:1649506048 key(0) value(0x7f2b3c0008c0)
pthread:1649506048 destructor value(0x7f2b3c0008c0)
pthread:1670485760 key(0) value(0x7f2b4c0008c0)
pthread:1670485760 destructor value(0x7f2b4c0008c0)


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。