Linux学习笔记:线程私有数据

在学习线程操作的过程中,我一直对线程私有数据的作用很困惑,不知道它到底有什么作用,但经过一段时间的探索后,我总结了一部分关于线程私有数据的用法,如果有不对或者不够详细的地方,请指出。

线程私有数据的实现:


线程的私有数据采用了一种被称为 "一键多值" 的技术,即一个键对应多个数值。


操作线程私有数据的函数主要有4个:

1> pthread_key_create();     创建一个键

2> pthread_key_delete();     删除一个键

3> pthread_setspecific();      将一个私有数据与键相关联

4> pthread_getspecific();      从一个键读取线程私有数据


这几个函数的声明如下:

#include <pthread.h>
int pthread_key_create (pthread_key_t * key, void (*destr_function) (void *)) ;
int pthread_key_delete (pthread_key_t key) ;
int pthread_setspecific (pthread_key_t key. const void * pointer) ;
int pthread_getspecific (pthread_key_t key) ;

函数的作用:

1> pthread_key_create():从Linux的TSD池中分配一项,将其值分配给第一个参数指向的key供以后访问使用,函数的第二个参数是一个函数指针,如果指针不为空,则在线程退出时将 以key所关联的数据为参数 调用destr_function(),释放分配的缓冲区。

2> phread_delete():该函数用来删除一个键。删除后,键所占的内存将被释放。需要注意的是,与该键关联的线程数据所占用的内存并不被释放。因此,线程数据的释放必须在释放键之前完成。

3> pthread_setspecific():该函数将pointer的值 (不是内容) 与key相关联。用pthread_setspecific为一个键指定新的线性数据时,线程必须先释放原有的线程数据用以回收空间。

4> pthread_getspecific():通过该函数得到与key相关联的数据。

"一键多值" 技术的实现靠的是一个关键数据结构数组,即TSD池,其结构如下:

static struct pthread_key_struct pthread_keys [PTHREAD_KESYS_MAX] = { {0,NULL} };




线程私有数据的用法:

线程分配私有数据之前,创建与该数据相关联的键,这个键可以被进程中所有线程使用,但每个线程把这个键与不同的线程私有数据地址进行关联。每次线程需要使用该私有数据时,就可以通过该键来获得私有数据的值。



线程私有数据的作用:

线程的私有数据需要和 线程函数的局部变量 区分开,这两者之间最主要的区别在于作用范围不同

线程的局部变量虽然也属于线程的私有数据,但它的作用范围只在线程函数中,对于线程中调用的其他函数来说,该变量是不可见的,除非线程函数将其当作参数传入所调用的函数中。

线程的私有数据则相当于线程中的全局变量,由于创建的键key是一个进程中的全局变量,所以进程中的所有函数都可以访问key,但键的特性使每个访问它的线程都会获得不同的值,即线程提前与其关联的数据。所以,当线程函数中的一个数据与key相关联后,对于线程所调用的每一个函数来说,该数据都是可见的

简单来讲,将线程中的一个数据变为线程的私有数据,就是将该数据的作用范围扩大到整个线程,变成了该线程中的全局变量,对于其他的线程来说,该线程的全局变量是不可见的。而线程中的局部变量作用范围仅限于定义该局部变量的函数,对于同一个线程调用的其他函数来说,该变量是不可见的。

为了更好的理解私有数据的作用,可以参照下列代码:

/*************************************************************************
	> File Name: pthread_test.c
	> Author: zhaobaojin 
	> BLOG: blog.csdn.net/zhaobaojin1006 
	> Mail: 1279742553@qq.com 
	> Created Time: 2015年07月30日 星期四 14时38分59秒
 ************************************************************************/
#include<stdio.h>
#include<pthread.h>

pthread_key_t key ;      /*创建一个键*/

int func(void) ;

void thread1(void *arg) ;      /*线程函数*/

void thread2(void *arg) ;

int main(void)
{
    int *status ;
    pthread_t thid1, thid2 ;
    pthread_key_create (&key, NULL) ;
    if (pthread_create (&thid1, NULL, (void *)thread1, NULL)  != 0 ) {       /*创建新线程1*/
        printf ("new thread create failed\n") ;
        return 0 ;
    }
    if (pthread_create (&thid2, NULL, (void *)thread2, NULL)  != 0 ) {       /*创建新线程2*/
        printf ("new thread create failed\n") ;
        return 0 ;
    }
    pthread_join (thid1, (void *)&status) ;
    pthread_join (thid2, (void *)&status) ;
    pthread_key_delete (key) ;
    return 0 ;
}


int func()
{
    /*新线程中调用函数打印key*/
    printf ("i am newthread:%u,i can read the key:%d\n", pthread_self(), pthread_getspecific (key)) ;

    return 0 ;
}


void thread1(void *arg)       /*线程1将一个线程函数中的局部变量跟key关联,调用func()打印跟key关联的值*/
{
    int tsd=5 ;
    pthread_setspecific( key , (void *)tsd ) ;      /*关联私有数据*/
    func();
    pthread_exit(0);
}


void thread2(void *arg)       /*线程2关联同一个key,并调用func()打印跟key关联的值*/
{
    int tsd=6 ;
    pthread_setspecific( key , (void *)tsd ) ;      /*关联私有数据*/
    func();
    pthread_exit(0);
}


程序中 thread1, thread2 是两个线程函数,都将自己的局部变量与key相关联,也都调用同一个 func() 函数来打印key中所存储的值。

运行结果如下:


从运行结果可以看出,不同线程调用 pthread_getspecific() 读取的key键值是不同的,而同一线程中调用的不同函数都可以直接获得私有数据,也即私有数据作用范围扩大到了线程的全局变量。


需要注意的是,在编译这段代码时,编译器会报警告,原因是代码中的

    int tsd=5 ;
    pthread_setspecific( key , (void *)tsd ) ;      /*关联私有数据*/

这两句代码很容易可以看出,程序将一个整型变量 tsd 强制类型转换成了 void 型指针,函数之所以 这样设计的是因为,操作系统中的 TSD池 提前并不知道线程需要存入的数据类型,故而将所有数据都先统一转换为 (void *) 型,到需要读取私有数据时再转换为原本的数据类型。

    printf ("i am newthread:%u,i can read the key:%d\n", pthread_self(), pthread_getspecific (key)) ;
读取私有数据的函数 pthread_getspecific() 返回值也是 (void *) 型,程序中私有数据在输出时则以 %d 类型输出。





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值