《UNIX环境高级编程》笔记--线程私有数据
2014-01-12 12:47
274 查看
线程私有数据时存储和查询与某个线程相关的数据的一种机制。把这种数据成为线程私有数据或线程特定数据的原因是,
希望每个线程都可以独立地访问数据副本,并不需要担心与其他线程的同步访问问题。
为什么要使用线程私有数据呢?原因有两个:
1.有时候需要维护基于每个线程的数据,因为线程ID并不能保证是小而连续的整数,所以不能简单地分配一个线程数据
数组,用线程ID作为数组的索引。即使线程ID确实是小而连续的整数,可能还希望有一些额外的保护,以防止某个线程的数
据与其他线程数据相混淆。
2.它提供了让基于进程的接口适应多线程环境的机制。一个很明显的实例就是errno,在多线程环境下,errno不能简单地
定义为一个全局变量,因为多个线程可能使用在读写该变量。为了让线程能够使用那些原本基于进程的线程调用和库例程,
errno被重新定义为线程私有数据。
在分配线程私有数据之前,需要创建于该数据关联的键,这个键将用于获取对线程私有数据的访问权,使用
pthread_key_create创建一个键。
创建的键存放在keyp指向的内存单元,这个键额可以被进程中的所有线程使用,但每个线程把这个键与不同的线程私有数据
地址进行关联。创建新键时,每个线程的数据地址设为null值。
除了创建键以外,pthread_key_create可以选择为该键关联析构函数,当线程退出时,如果数据地址已经被设置为非null,那
么析构函数就会被调用,它唯一的参数就是该数据地址。如果传入的destructor参数为null,就表明没有析构函数与键关联。
当线程调用pthread_exit或者线程执行返回,正常退出时,析构函数就会被调用,但是如果线程调用了exit、_exit、_Exit、abort
或者出现其他非正常的退出时,就不会调用析构函数。
线程通常使用malloc为线程私有数据分配内存空间,析构函数通常释放以分配的内存,如果线程没有释放内存就退出了,那么
这块内存就会泄露。
如果多个线程都调用了pthread_key_create函数, 那么有些线程可能看到某个键值,而其他的线程看到的可能是另一个不
同的线程,解决这种竞争的方法是使用pthread_once.
initflag必须是一个非本地变量(全局变量或静态变量),必须初始化为PTHREAD_ONCE_INIT.
如果每个线程都调用
pthread_once,系统就能保证初始化例程initfn只被调用一次。
对所有的线程,都可以通过调用pthread_key_delete来取消键与线程私有数据之间的关联关系。
键一旦创建,就可以用过调用pthread_setspecific函数把键和线程私有数据关联起来,可以通过pthread_getspecific函数
获取线程私有数据的地址。
实践:
希望每个线程都可以独立地访问数据副本,并不需要担心与其他线程的同步访问问题。
为什么要使用线程私有数据呢?原因有两个:
1.有时候需要维护基于每个线程的数据,因为线程ID并不能保证是小而连续的整数,所以不能简单地分配一个线程数据
数组,用线程ID作为数组的索引。即使线程ID确实是小而连续的整数,可能还希望有一些额外的保护,以防止某个线程的数
据与其他线程数据相混淆。
2.它提供了让基于进程的接口适应多线程环境的机制。一个很明显的实例就是errno,在多线程环境下,errno不能简单地
定义为一个全局变量,因为多个线程可能使用在读写该变量。为了让线程能够使用那些原本基于进程的线程调用和库例程,
errno被重新定义为线程私有数据。
在分配线程私有数据之前,需要创建于该数据关联的键,这个键将用于获取对线程私有数据的访问权,使用
pthread_key_create创建一个键。
#include<pthread.h> int pthread_key_create(pthread_key_t *keyp, void (*destructor) (void*)); //成功返回0,否则返回错误编号。
创建的键存放在keyp指向的内存单元,这个键额可以被进程中的所有线程使用,但每个线程把这个键与不同的线程私有数据
地址进行关联。创建新键时,每个线程的数据地址设为null值。
除了创建键以外,pthread_key_create可以选择为该键关联析构函数,当线程退出时,如果数据地址已经被设置为非null,那
么析构函数就会被调用,它唯一的参数就是该数据地址。如果传入的destructor参数为null,就表明没有析构函数与键关联。
当线程调用pthread_exit或者线程执行返回,正常退出时,析构函数就会被调用,但是如果线程调用了exit、_exit、_Exit、abort
或者出现其他非正常的退出时,就不会调用析构函数。
线程通常使用malloc为线程私有数据分配内存空间,析构函数通常释放以分配的内存,如果线程没有释放内存就退出了,那么
这块内存就会泄露。
如果多个线程都调用了pthread_key_create函数, 那么有些线程可能看到某个键值,而其他的线程看到的可能是另一个不
同的线程,解决这种竞争的方法是使用pthread_once.
#include<pthread.h> pthread_once_t initflag = PTHREAD_ONCE_INIT; int pthread_once(pthread_once_t *initflag, void(*initfn)(void)); //成功则返回0,否则返回错误编号。
initflag必须是一个非本地变量(全局变量或静态变量),必须初始化为PTHREAD_ONCE_INIT.
如果每个线程都调用
pthread_once,系统就能保证初始化例程initfn只被调用一次。
对所有的线程,都可以通过调用pthread_key_delete来取消键与线程私有数据之间的关联关系。
#include<pthread.h> int pthread_key_delete(pthread_key_t *key); //成功则返回0,否则返回错误编号。pthread_key_delete并不会激活与键相关的析构函数。
键一旦创建,就可以用过调用pthread_setspecific函数把键和线程私有数据关联起来,可以通过pthread_getspecific函数
获取线程私有数据的地址。
#include<pthread.h> void *pthread_getspecific(pthread_key_t key); //返回线程私有数据值,没有值与键关联则返回NULL。 int pthread_setspecific(pthread_key_t key, const void *value); //成功则返回0,否则返回错误编号。
实践:
#include<limits.h> #include<string.h> #include<pthread.h> #include<stdlib.h> static pthread_key_t key; static pthread_once_t init_done = PTHREAD_ONCE_INIT; pthread_mutex_t env_mutex = PTHREAD_MUTEX_INITIALIZER; extern char **environ; static void thread_init(void){ pthread_key_create(&key, free); } char* getenv(const char *name){ int i, len; char *envbuf; pthread_once(*init_done, thread_init); pthread_mutex_lock(&env_mutex); envbuf = (char*)pthread_getspecific(key); if(envbuf == NULL){ envbuf = malloc(ARG_MAX); if(envbuf == NULL){ pthread_mutex_unlock(&env_mutex); return NULL; } pthread_setpecific(key,envbuf); } len = str;en(name); for(i=0; environ[i] != NULL; i++){ if((!strncmp(name,environ[i],len) == 0) && (environ[i][len] == '=')){ strcpy(envbuf, &environ[i][len+1]); phread_mutex_unlock(&env_mutex); return envbuf; } } pthread_mutex_unlock(&env_mutex); return NULL; }这个函数根据环境变量的名字获取名字对应的值。
相关文章推荐
- linux api笔记(6):线程(四) 线程私有数据
- linux多线程学习笔记六--一次性初始化和线程私有数据【转】
- linux多线程学习笔记六--一次性初始化和线程私有数据
- UNIX环境高级编程——线程私有数据
- ZT linux 线程私有数据之 一键多值技术
- 线程私有数据
- 多个线程访问共享对象和数据的方式-笔记整理5
- Django学习笔记5 让用户拥有私有数据 访问限制
- [GNU/Linux] Linux系统调用-线程相关(三):私有数据
- Linux线程私有数据pthread_key_t
- 学习笔记―线程返回数据
- 实现一个线程安全的内存池(使用线程私有数据机制TSD来实现)
- unix/linux下线程私有数据实现原理及使用方法
- linux线程私有数据---TSD池
- 线程私有数据
- Posix线程编程指南(2)——线程私有数据
- Java多线程学习笔记——从Java JVM对多线程数据同步的一些理解
- 第10章 线程控制(3)_线程私有数据
- 学习笔记TF049:TensorFlow 模型存储加载、队列线程、加载数据、自定义操作
- C++学习笔记之线程:数据共享与竞争,线程死锁