《Linux C编程实战》笔记:线程私有数据

在多线程环境下,进程内的所有线程共享进程的数据空间,因此全局变量为所有线程共有。在程序设计中有时需要保存线程自己的全局变量,这种特殊的变量仅在某个线程内部有效。如常见的变量errno,它返回标准的出错代码。errno不应该是一个局部变量,几乎每个函数都应该可以访问它;但它又不能作为是一个全局变量,否则在一个线程 里输出的很可能是另一个线程的出错信息,这个问题可以通过创建线程的私有数据(Thread-specific Data,或TSD)来解决。
在线程内部,线程私有数据可以被各个函数访问,但它对其他线程是屏蔽的。线程私有数据采用了一种被称为一键多值的技术,即一个键对应多个数值。访问数据时都是通过键值来访问,好像是对一个变量进行访问,其实是在访问不同的数据。使用线程私有数据时,首先要为每个线程数据创建一个相关联的键。在各个线程内部,都使用这个公用的键来指代线程数据,但是在不同的线程中这个键代表的数据是不同的。操作线程私有数据的函数主要有4个:
pthread_key_create (创建一个键), pthread_setspecific(为一个键 设置线程私有数据),pthread_getspecifie(从一个键读取线程私有数据)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);
  1. pthread_key_create:

    • 目的:用于创建一个线程特定数据的键。
    • 参数:
      • key:一个指向 pthread_key_t 变量的指针,用于存储键。
      • destr_function:一个指向析构函数的指针,在线程退出时会调用该函数,并以key所关联的数据作为参数。
  2. pthread_setspecific:

    • 目的:用于将线程特定值与键关联起来。
    • 参数:
      • key:之前使用 pthread_key_create 创建的键。
      • pointer:要与当前线程的键关联的数据的指针。
  3. pthread_getspecific:

    • 目的:检索与给定键关联的线程特定值。
    • 参数:
      • key:要检索当前线程的键关联的线程特定值。
    • 返回值:指向与键关联的线程特定数据的指针,用于当前线程。
  4. pthread_key_delete:

    • 目的:用于删除线程特定数据的键。
    • 参数:
      • key:使用 pthread_key_create 创建的要删除的键。
    • 返回值:成功时返回0,如果发生错误则返回错误代码。
    • 删除后,键所占用的内存被释放,与键关联的线程数据所占用的内存并不被释放。所以,要记得先释放线程数据。

可以这么理解,键值是对所有线程都可见的全局变量,但是不同线程可以让同一键值关联到线程自身的数据,从而实现不同线程通过同一全局的键值得到不同数据(通过getspecific获得)。

示例程序

书上示例程序运行起来也是问题重重,我也改了一下

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
pthread_key_t key;
void *thread2(void *arg){
    int tsd=5;
    printf("thread %d is running\n",pthread_self());
    pthread_setspecific(key,(const void *)&tsd);//线程2给key关联到线程2的tsd
    printf("thread %d returns %d\n",pthread_self(),*(int *)pthread_getspecific(key));
    return nullptr;
}
void *thread1(void *arg){
    int tsd=0;
    pthread_t thid2;//线程1又创建了一个线程2
    printf("thread %d is running\n",pthread_self());
    pthread_setspecific(key,(const void *)&tsd);//这是线程1里面给key关联到线程1的tsd
    pthread_create(&thid2,nullptr,thread2,nullptr);
    sleep(5);
    printf("thread %d returns %d\n",pthread_self(),*(int *)pthread_getspecific(key));
    return nullptr;
}
int main(){
    pthread_t thid1;//线程1
    printf("main thread begins running \n");
    pthread_key_create(&key,nullptr);//创建键值,没有清理函数所以第二个参数给了null
    pthread_create(&thid1,nullptr,thread1,nullptr);
    sleep(10);
    pthread_key_delete(key);
    printf("main thread exit\n");
    return 0;
}

运行结果如图,可以看到不同的线程对key执行getspecific会得到不同的值

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值