美文网首页
线程特定数据

线程特定数据

作者: Junior888 | 来源:发表于2018-08-18 23:01 被阅读0次

Linux多线程实践(4) --线程特定数据

1. 线程特定数据是什么?

单线程 C 程序有两类基本数据:局部数据和全局数据。对于多线程 C 程序,添加了第三类
数据:线程特定数据。线程特定数据与全局数据非常相似,区别在于前者为线程专有。

在单线程程序中,我们经常要用到"全局变量"以实现多个函数间共享数据, 然而在多线程环境下,由于数据空间是共享的,因此全局变量也为所有线程所共有。但有时应用程序设计中有必要提供线程私有的全局变量,仅在某个线程中有效,但却可以跨多个函数访问。POSIX线程库通过维护一定的数据结构来解决这个问题,这个些数据称为(Thread-specific-data或 TSD)。

线程特定数据基于每线程进行维护。TSD(特定于线程的数据)是定义和引用线程专用数
据的唯一方法。每个线程特定数据项都与一个作用于进程内所有线程的键关联。通过使用
key,线程可以访问基于每线程进行维护的指针 (void *)。

线程特定数据

从上图可知:当调用pthread_key_create 后会产生一个所有线程都可见的线程特定数据(TSD)的键值(如上图中所有的线程都会得到一个pkey[1]的值), 但是这个键所指向的真实数据却是不同的,虽然都是pkey[1], 但是他们并不是指向同一块内存,而是指向了只属于自己的实际数据, 因此, 如果线程0更改了pkey[1]所指向的数据, 而并不能够影像到线程n;

在线程调用pthread_setspecific后会将每个线程的特定数据与thread_key_t绑定起来,虽然只有一个pthread_key_t,但每个线程的特定数据是独立的内存空间,当线程退出时会执行destructor 函数。

2. 常用函数有哪些?

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);
//设置线程特定数据

void * pthread_getspecific(pthread_key_t key);
 //获取线程特定数据

3. 示例

/** 示例1: 设置/获取线程特定数据
在两个线程中分别设置/获取线程特定数据, 查看两个线程中的数据是否是一样的(肯定是不一样的O(∩_∩)O~)
**/
pthread_key_t key;
typedef struct Tsd
{
    pthread_t tid;
    char *str;
} tsd_t;
//用来销毁每个线程所指向的实际数据
void destructor_function(void *value)
{
    free(value);
    cout << "destructor ..." << endl;
}
 
void *thread_routine(void *args)
{
    //设置线程特定数据
    tsd_t *value = (tsd_t *)malloc(sizeof(tsd_t));
    value->tid = pthread_self();
    value->str = (char *)args;
    pthread_setspecific(key, value);
    printf("%s setspecific, address: %p\n", (char *)args, value);
 
    //获取线程特定数据
    value = (tsd_t *)pthread_getspecific(key);
    printf("tid: 0x%x, str = %s\n", (unsigned int)value->tid, value->str);
    sleep(2);
 
    //再次获取线程特定数据
    value = (tsd_t *)pthread_getspecific(key);
    printf("tid: 0x%x, str = %s\n", (unsigned int)value->tid, value->str);
 
    pthread_exit(NULL);
}
 
int main()
{
    //这样每个线程当中都会有一个key可用了,
    //但是每个key所绑定的实际区域需要每个线程自己指定
    pthread_key_create(&key, destructor_function);
 
    pthread_t tid1, tid2;
    pthread_create(&tid1, NULL, thread_routine, (void *)"thread1");
    pthread_create(&tid2, NULL, thread_routine, (void *)"thread2");
 
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    pthread_key_delete(key);
 
    return 0;
}
/** 示例2:运用pthread_once, 让key只初始化一次
注意: 将对key的初始化放入到init_routine中
**/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>

pthread_key_t key;
pthread_once_t once_control = PTHREAD_ONCE_INIT;
typedef struct Tsd
{
    pthread_t tid;
    char *str;
} tsd_t;
 
//线程特定数据销毁函数,
//用来销毁每个线程所指向的实际数据
void destructor_function(void *value)
{
    free(value);
    printf("destructor ...\n");
}
 
//初始化函数, 将对key的初始化放入该函数中,
//可以保证inti_routine函数只运行一次
void init_routine()
{
    pthread_key_create(&key, destructor_function);
    printf("init...\n");
}
 
void *thread_routine(void *args)
{
    pthread_once(&once_control, init_routine);
 
    //设置线程特定数据
    tsd_t *value = (tsd_t *)malloc(sizeof(tsd_t));
    value->tid = pthread_self();
    value->str = (char *)args;
    pthread_setspecific(key, value);
    printf("%s setspecific, address: %p\n", (char *)args, value);
 
    //获取线程特定数据
    value = (tsd_t *)pthread_getspecific(key);
    printf("tid: 0x%x, str = %s\n", (unsigned int)value->tid, value->str);
    sleep(2);
 
    //再次获取线程特定数据
    value = (tsd_t *)pthread_getspecific(key);
    printf("tid: 0x%x, str = %s\n", (unsigned int)value->tid, value->str);
 
    pthread_exit(NULL);
}
 
int main()
{
    pthread_t tid1, tid2;
    pthread_create(&tid1, NULL, thread_routine, (void *)"thread1");
    pthread_create(&tid2, NULL, thread_routine, (void *)"thread2");
 
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    pthread_key_delete(key);
 
    return 0;
}

执行结果如下所示:

junior@ubuntu:~/thread$ ./thread_spec 
init...
thread2 setspecific, address: 0x7f2584000f30
tid: 0x8971a700, str = thread2
thread1 setspecific, address: 0x7f257c000b20
tid: 0x89f1b700, str = thread1
tid: 0x8971a700, str = thread2
destructor ...
tid: 0x89f1b700, str = thread1
destructor ...

相关文章

  • 线程特定数据

    Linux多线程实践(4) --线程特定数据 1. 线程特定数据是什么? 单线程 C 程序有两类基本数据:局部数据...

  • APUE读书笔记-12线程控制(4)

    6、线程特定数据 这里的线程特定数据也就是线程私有数据,是一种只存取指定线程相关的数据的一种机制。使用线程私有数据...

  • { 4 }CPP_使用互斥量保护共享数据

    当一个线程使用特定互斥量锁住共享数据时,其他线程想要访问锁住的数据,都必须等到之前那个线程堆数据进行解锁后,才能进...

  • 线程间通讯

    线程间通讯 线程间通信的体现:1个线程传递数据给另1个线程 ,在1个线程中执行完特定任务后,转到...

  • 多线程局部变量:threading.local()

    参考博客 多线程局部变量之threading.local()用法 一、线程特定的数据 在线程中有些资源需要锁定(如...

  • Java8源码阅读 - ThreadLocal

    有时候我们想要将某些数据和特定的线程进行关联,可以使用一个全局Map将线程id和数据做映射,当然我们还可以使用JD...

  • ThreadLocal

    设计理念 为每个线程创造一个资源的复本。将每一个线程存取数据的行为加以隔离,实现的方法就是给予每个线程一个特定空间...

  • Telegram开源项目之DispatchQueue

    DispatchQueue介绍 在特定的线程(单线程)下串行执行的任务队列 DispatchQueue作用 在特定...

  • 线程安全性(一)

    参考线程安全性总结 CountDownLatchCountDownLatch 可以阻塞线程并保证线程在满足某种特定...

  • Java 知识小集 第 4 期

    1. 锁的两种主要特性: 互斥:同一时间只允许一个线程持有某个特定的锁。线程持有该锁相当于令牌去访问线程共享的数据...

网友评论

      本文标题:线程特定数据

      本文链接:https://www.haomeiwen.com/subject/cufxiftx.html