计算机基础--线程私有变量

多线程环境下的私有数据(Thread-specific Data, TSD):

    线程拥有自己的 全局变量,这种特殊的变量仅在某个线程内部有效。线程的私有数据可以被其内部的所有函数访问,但是对其他线程是屏蔽的。 线程私有数据采用了一种称为一键多值的技术,即一个键对应多个数值。访问数据时都是通过键值来访问,好像是对一个变量进行访问,其实是在访问不同的数据。
    操作 线程私有数据的函数主要有4个:
        pthread_key_create(创建一个键),pthread_setspecific(为一个键设置 线程私有数据),pthread_getspecific(从一个键读取 线程私有数据),pthread_key_delete(删除一个键)。
        #include <pthread.h>
        int pthread_key_create(pthread_key_t *key, void (*destr_function)(void *));
        int pthread_setspecific(pthread_key_t key, const void * pointer);
        void* pthread_getspecific(pthread_key_t key);
        int pthread_key_delete(pthread_key_t key);


一.  概念及作用

在单线程程序中,我们经常要用到"全局变量"以实现多个函数间共享数据。在多线程环境下,由于数据空间是共享的,因此全局变量也为所有线程所共  有。但有时应用程序设计中有必要提供线程私有的全局变量,仅在某个线程中有效,但却可以跨多个函数访问,比如程序可能需要每个线程维护一个链表,而使用相  同的函数操作,最简单的办法就是使用同名而不同变量地址的线程相关数据结构。这样的数据结构可以由 Posix 线程库维护,称为线程私有数据  (Thread-specific Data,或 TSD)。

二.  创建和注销
Posix 定义了两个 API 分别用来创建和注销 TSD:
int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *)) 该函数从 TSD 池中分配一项,将其值赋给 key 供以后访问使用。如果 destr_function 不为空,在线程退出(pthread_exit())时将以 key 所关联的数据为参数调用 destr_function(),以释放分配的缓冲区。不论哪个线程调用 pthread_key_create(),所创建的 key 都是所有线程可访问的,但各个线程可根据自己的需要往 key 中填入不同的值,这就相当于提供了一个同名而不同值的全局变量。在 LinuxThreads 的实现中,TSD 池用一个结构数组表示:static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] = { { 0, NULL } };
创建一个 TSD 就相当于将结构数组中的某一项设置为"in_use",并将其索引返回给*key,然后设置 destructor 函数为 destr_function。
注销一个 TSD 采用如下 API:
int pthread_key_delete(pthread_key_t key) 这个函数并不检查当前是否有线程正使用该 TSD,也不会调用清理函数(destr_function),而只是将 TSD 释放以供下一次调用  pthread_key_create()使用。在 LinuxThreads 中,它还会将与之相关的线程数据项设为 NULL(见"访问")。
三.  访问
TSD 的读写都通过专门的 Posix Thread 函数进行,其 API 定义如下: int pthread_setspecific(pthread_key_t key, const void *pointer) void * pthread_getspecific(pthread_key_t key) 写入(pthread_setspecific())时,将 pointer 的值(不是所指的内容)与 key 相关联,而相应的读出函数则将与 key 相关联的数据读出来。数据类型都设为 void *,因此可以指向任何类型的数据。在 LinuxThreads 中,使用了一个位于线程描述结构(_pthread_descr_struct)中的二维 void *

指 针 数 组 来 存 放 与 key 关 联 的 数 据 , 数 组 大 小 由 以 下 几 个 宏 来 说 明 :   #define PTHREAD_KEY_2NDLEVEL_SIZE 32 #define PTHREAD_KEY_1STLEVEL_SIZE \ ((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1) / PTHREAD_KEY_2NDLEVEL_SIZE) 其中在/usr/include/bits/local_lim.h 中定义了 PTHREAD_KEYS_MAX 为 1024,因此一维数组大小为 32。而具体存放的位置由 key 值经过以下计算得到: idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE 也就是说,数据存放与一个 32×32 的稀疏矩阵中。同样,访问的时候也由 key 值经过类似计算得到数据所在位置索引,再取出其中内容返回。

四. 使用范例
以下这个例子说明如何使用这一机制达到存储线程私有数据的目的。

  1. #include <stdio.h>   
  2. #include <pthread.h>   
  3.   
  4. pthread_key_t key;   
  5.   
  6. void echomsg(int t)   
  7. {   
  8. printf("destructor excuted in thread %d,param=%d\n",pthread_self(),t);   
  9. }   
  10.   
  11. void * child1(void *arg)   
  12. {   
  13. int tid=pthread_self();   
  14. printf("thread %d enter\n",tid);   
  15. pthread_setspecific(key,(void *)tid);   
  16. sleep(2);   
  17. printf("thread %d returns %d\n",tid,pthread_getspecific(key));   
  18. sleep(5);   
  19. }   
  20.   
  21. void * child2(void *arg)   
  22. {   
  23. int tid=pthread_self();   
  24. printf("thread %d enter\n",tid);   
  25. pthread_setspecific(key,(void *)tid);   
  26. sleep(1);   
  27. printf("thread %d returns %d\n",tid,pthread_getspecific(key));   
  28. sleep(5);   
  29. }   
  30.   
  31. int main(void)   
  32. {   
  33. int tid1,tid2;   
  34.   
  35. printf("hello\n");   
  36. pthread_key_create(&key,echomsg);   
  37. pthread_create(&tid1,NULL,child1,NULL);   
  38. pthread_create(&tid2,NULL,child2,NULL);   
  39. sleep(10);   
  40. pthread_key_delete(key);   
  41. printf("main thread exit\n");   
  42. return 0;   
  43. }   

运行结果如下:

hello
thread 1082350784 enter
thread 1090739264 enter
thread 1090739264 returns 1090739264
thread 1082350784 returns 1082350784
main thread exit

给例程创建两个线程分别设置同一个线程私有数据为自己的线程ID,为了检验其私有性,程序错开了两个线程私有数据的写入和读出的时间,从程序运行结果可以看出,两个线程对TSD的修改互不干扰。同时,当线程退出时,清理函数会自动执行,参数为tid。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值