《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会得到不同的值

相关推荐

  1. Linux C编程实战笔记线终止

    2024-01-14 01:28:02       47 阅读
  2. linux 线笔记

    2024-01-14 01:28:02       52 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-14 01:28:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-14 01:28:02       101 阅读
  3. 在Django里面运行非项目文件

    2024-01-14 01:28:02       82 阅读
  4. Python语言-面向对象

    2024-01-14 01:28:02       91 阅读

热门阅读

  1. argc和argv参数

    2024-01-14 01:28:02       70 阅读
  2. SpringSecurity入门demo(三)多用户身份认证

    2024-01-14 01:28:02       66 阅读
  3. [蓝桥杯 2015 省 A] 饮料换购

    2024-01-14 01:28:02       62 阅读
  4. AcWing:4965. 三国游戏

    2024-01-14 01:28:02       61 阅读
  5. 【Kotlin】中英数字混合等多种情况下的排序方式

    2024-01-14 01:28:02       59 阅读
  6. OLAP型数据库 ClickHouse的简介 应用场景 优势 不足

    2024-01-14 01:28:02       63 阅读
  7. xtu-c语言考试复习

    2024-01-14 01:28:02       60 阅读
  8. C#的索引和范围运算符的用法

    2024-01-14 01:28:02       47 阅读
  9. 一个Pytorch 的简单的分类本地图片的训练AI例子

    2024-01-14 01:28:02       64 阅读
  10. 50天精通Golang(第16天)

    2024-01-14 01:28:02       63 阅读
  11. Linux上对大于2T的硬盘分区

    2024-01-14 01:28:02       58 阅读