线程特定数据 Thread Specified Data
来源:互联网 发布:旅游策划师 知乎 编辑:程序博客网 时间:2024/06/07 13:50
1、为什么需要用到线程特定数据?
因为在单个线程的程序中,当我们调用同一个函数多次,若其中有静态、全局变量,该变量会随着每一次调用发生变化。
然而在多线程中,当多个线程同时调用同一个函数,若该函数没有全局、静态变量,那么不会引发错误;否则,我们就需要用到锁来解决问题。
这里提供的线程特定数据,是使线程函数变为线程安全的一个常用技巧
2、每一个系统支持的线程特定元素限制不一样。POSIX要求这个限制不小于128(对每个进程而言)。系统为每个【进程】维护一个我们称为key结构的结构数组
key结构中的标志指示某个元素是否正在被使用。
当一个线程调用pthread_key_create创建一个新的线程特定元素时,系统搜索其key结构数组找出第一个不在使用的元素,返回其索引
如图:
3、进程除了维护一个进程级别的key数组,系统还在进程内维护关于每个特定线程的多条信息。这些特定于线程的结构我们称为Pthread结构
其中部分内容为称为pkey数组的一个128个元素的指针数组
如图:
4、那么举个例子,该例子的步骤如下:
1、一个进程被启动,多个线程被创建
2、其中一个线程是首个调用函数readline()的线程。进入readline函数后,程序调用pthread_key_create。系统在key数组中找到一个未用的元素后,把它的索引返回给用户,假设是1。
这里我们将会使用pthread_once函数来确保pthread_key_create只被调用一次,且只被第一个调用pthread_key_create的线程调用。
3、接着,在readline中,程序调用pthread_getspecific函数获取本线程专属的pkey[1]的值,我们发现它是一个空指针。于是我们调用malloc为我们分配内存空间,并调用pthread_setspecific函数将pkey[1]指向刚刚分配的内存空间,保存本线程特定数据的信息,
4、另一个线程这是调用readline函数,当然可能刚刚的线程依旧在readline函数中运行。回归到这个新的线程中,我们的readline函数调用pthread_once试图调用pthread__key_create来初始化键,不过既然初始化已经调用过了,它就不再会被调用
5、readline调用pthread_getspecific发现本线程的pkey[n]是空的,就跟之前线程的处理方式一样,准备去申请空间并保存属于自己线程的特定数据
6、每个线程都在使用属于自己的数据
7、在每个线程函数调用结束后,如何释放这些申请的内存空间呢?
即使用pthread_key_create第二个参数,它指向的就是析构函数(跟C++里的析构一个意思)
以下就是上面步骤中提到的函数:
还有这两个函数:
接下来我给一个自己实验用的实例:
运行结果为:
因为在单个线程的程序中,当我们调用同一个函数多次,若其中有静态、全局变量,该变量会随着每一次调用发生变化。
然而在多线程中,当多个线程同时调用同一个函数,若该函数没有全局、静态变量,那么不会引发错误;否则,我们就需要用到锁来解决问题。
这里提供的线程特定数据,是使线程函数变为线程安全的一个常用技巧
2、每一个系统支持的线程特定元素限制不一样。POSIX要求这个限制不小于128(对每个进程而言)。系统为每个【进程】维护一个我们称为key结构的结构数组
key结构中的标志指示某个元素是否正在被使用。
当一个线程调用pthread_key_create创建一个新的线程特定元素时,系统搜索其key结构数组找出第一个不在使用的元素,返回其索引
如图:
3、进程除了维护一个进程级别的key数组,系统还在进程内维护关于每个特定线程的多条信息。这些特定于线程的结构我们称为Pthread结构
其中部分内容为称为pkey数组的一个128个元素的指针数组
如图:
当我们调用pthread_key_create创建一个键时,系统告诉我们这个键的索引。每个线程随后可以在该键对应下标的pkey数组中存储一个自己的值。
4、那么举个例子,该例子的步骤如下:
1、一个进程被启动,多个线程被创建
2、其中一个线程是首个调用函数readline()的线程。进入readline函数后,程序调用pthread_key_create。系统在key数组中找到一个未用的元素后,把它的索引返回给用户,假设是1。
这里我们将会使用pthread_once函数来确保pthread_key_create只被调用一次,且只被第一个调用pthread_key_create的线程调用。
3、接着,在readline中,程序调用pthread_getspecific函数获取本线程专属的pkey[1]的值,我们发现它是一个空指针。于是我们调用malloc为我们分配内存空间,并调用pthread_setspecific函数将pkey[1]指向刚刚分配的内存空间,保存本线程特定数据的信息,
4、另一个线程这是调用readline函数,当然可能刚刚的线程依旧在readline函数中运行。回归到这个新的线程中,我们的readline函数调用pthread_once试图调用pthread__key_create来初始化键,不过既然初始化已经调用过了,它就不再会被调用
5、readline调用pthread_getspecific发现本线程的pkey[n]是空的,就跟之前线程的处理方式一样,准备去申请空间并保存属于自己线程的特定数据
6、每个线程都在使用属于自己的数据
7、在每个线程函数调用结束后,如何释放这些申请的内存空间呢?
即使用pthread_key_create第二个参数,它指向的就是析构函数(跟C++里的析构一个意思)
以下就是上面步骤中提到的函数:
int pthread_key_create(pthread_key_t *keyptr, void (*destroy)(void *value));int pthread_once(pthread_once_t *onceptr, void (*init)(void));
//功能:本函数使用初值为PTHREAD_ONCE_INIT的once_control变量保证init_routine()函数在本进程执行序列中仅执行一次。pthread_key_t r1_key;pthread_once_t re_once = PTHREAD_ONCE_INIT;//定义析构函数,释放空间void readline_destructor(void *ptr){ free(ptr);}//初始化函数 void readline_once(void){ pthread_key_create(&r1_key,readline_destructor);}ssize_treadline(...){ .... pthread_once(&r1_once,readline); if((ptr = pthread_getspecific(r1_key)) == NULL) { ptr = malloc(....); //设置键值对。 pthread_setspecific(r1_key,ptr); .... } ..... }
还有这两个函数:
void *pthread_getspecific(pthread_key_t key);int pthread_setspecific(pthread_key_t key, const void *value);
接下来我给一个自己实验用的实例:
#include "unp.h"pthread_key_t key;void release();void *thread_f1(void *);void *thread_f2(void *);int main(int ac, char *av[]){ pthread_t tid1, tid2; printf("start to create threads\n"); pthread_key_create(&key,release); //创建两个实验用线程 pthread_create(&tid1,NULL,&thread_f1,NULL); pthread_create(&tid2,NULL,&thread_f2,NULL); sleep(6); pthread_key_delete(key); printf("bye\n"); exit(0);}//用定时器来把时间片交错,更能体现特定数据的真实性//线程1void *thread_f1(void *arg){ int tid = pthread_self(); printf("thread %d start\n",tid); pthread_setspecific(key,(void *)&tid); sleep(3); printf("thread %d returns %d\n",tid,*(int *)pthread_getspecific(key)); sleep(2); return NULL;}//线程2void *thread_f2(void *arg){ int tid = pthread_self(); sleep(1); printf("thread %d start\n",tid); pthread_setspecific(key,(void *)&tid); sleep(1); printf("thread %d returns %d\n",tid,*(int *)pthread_getspecific(key)); sleep(2); return NULL;}//析构函数void release(){ printf("this thread specific date is over\n");}
运行结果为:
$ ./TSD start to create threadsthread 1506096896 startthread 1495607040 startthread 1495607040 returns 1495607040thread 1506096896 returns 1506096896this thread specific date is overthis thread specific date is overbye
0 0
- 线程特定数据 Thread Specified Data
- 线程的属性和 线程特定数据 Thread-specific Data
- 线程局部存储 Thread Local Storage 线程特定数据 Thread-Specific Data
- linux网络编程之posix 线程(二):线程的属性和 线程特定数据 Thread-specific Data
- TSD(Thread Specific Data)线程专有数据
- 线程私有数据(Thread-Specific Data)
- 线程专有数据(Thread-Specific Data)
- Thread-Specific Data(线程私有数据)
- Thread-Specific Data(TSD)线程私有数据
- 线程私有数据(Thread-specific Data,或TSD)
- 线程的私有数据(TSD-Thread-Specific Data)
- 线程特定数据
- 线程特定数据详解
- 线程特定数据
- 线程特定数据
- 线程特定数据
- 线程特定数据
- 线程特定数据
- 总结 & 思考 & 平常心
- 山寨QQ新得
- C#操作word定位光标
- jsp 返回并刷新上一页
- Rotate List
- 线程特定数据 Thread Specified Data
- Mysql中的注释
- 立场声明--“没有丑女人只有懒女人;没有牛X的人,勤奋的你会比他更牛X”
- 【微积分】CodeForces 185B Mushroom Scientists
- 使用corosync+pacemaker构建高可用集群(转)
- intent传递对象——序列化
- Loading Large Bitmaps Efficiently
- 点滴积累
- 快餐生活时代