一个标准的线程由 线程ID 当前指令指针(PC) 寄存器集合 和 堆栈组成
见--码农自我修养 线程部分
1.为什么需要线程私有数据: 原
因一:有时候需要维护基于每个线程的数据,用线程ID作为索引。因为线程ID不能保证是小而连续的整数,所以不能简单的分配一个线程数据数组,用线程ID
作为数组的索引。即使线程ID确实是小而连续的整数,可能还希望有一些额外的保护,以防止某个线程的数据和其它线程的数据相混淆。
原因二:可以让基于进程的接口适应多线程环境,比如errno,线程出现以前errno被定义成进程环境中全局可访问的整数,线程出现以后,为了让线程也能使用那些原本基于进程的系统调用和库例程,errno被重新定义成线程私有数据。
(参考APUE2)
2.进程中的所有线程都可以访问进程的整个地址空间,除非使用寄存器(一个线程真正拥有的唯一私有存储是处理器寄存器),线程没有办法阻止其它线程访问它的数据,线程私有数据也不例外,但是管理线程私有数据的函数可以提高线程间的数据独立性。
3.int pthread_key_create(pthread_key_t *keyp, void (*destructor)(void *));
在分配(malloc)线程私有数据之前,需要创建和线程私有数据相关联的键(key),这个键的功能是获得对线程私有数据的访问权。
如
果创建一个线程私有数据键,必须保证Pthread_key_create对于每个Pthread_key_t变量仅仅被调用一次,因为如果一个键被创建
两次,其实是在创建两个不同的键,第二个键将覆盖第一个键,第一个键以及任何线程可能为其关联的线程私有数据值将丢失。
创建新键时,每个线程的数据地址设为NULL。
4.关于析构函数void (*destructor)(void *):
当线程退出时,如果线程私有数据地址被置为非NULL值,那么析构函数就会被调用。
当线程调用pthread_exit或者线程执行返回,正常退出时,析构函数就会被调用,但是如果线程调用了exit系列函数或者abort或者其它非正常退出时,就不会调用析构函数。
5.
线程退出时,线程私有数据的析构函数将按照OS实现定义的顺序被调用。析构函数可能调用另外一个函数,而该函数可能创建新的线程私有数据而且把这个线程私
有数据和当前的键关联起来。当所有的析构函数都调用完成以后,系统会检查是否有非NULL的线程私有数据值与键关联,如果有的话,再次调用析构函数,这个
过程一直重复到线程所有的键都为NULL值线程私有数据,或者已经做了PTHREAD_DESTRUCTOR_ITERATIONS中定义的最大次数的尝
试.
当下爱你成退出时,Pthreads在进程汇总检查所有的线程私有数据键,并且将不是NULL的线程私有数据简置NULL,然后调用键的destructor函数。
6.int pthread_delete(pthread_key_t *keyp),注意调用pthread_delete不会激活与键关联的析构函数,容易造成内存泄露。
当删除线程私有数据键的时候,不会影响任何线程对该键设置的线程私有数据值,甚至不影响调用线程当前键值,所以容易造成内存泄露,如果你不记得释放所有线程内与该键相关联的私有数据空间的话。
使用已经删除的私有数据键将导致未定义的行为。
编程建议:最后不删除线程私有数据键!!!尤其当一些线程仍然持有该键的值时,就更不该释放该键!!!
7.需要确保分配的键不会由于初始化阶段的竞争而发生变动。(使用pthread_once避免)
容易发生竞争的代码段:
void destructor(void *);
pthread_key_t key;
int flag;
int threadfun(void *arg)
{
if(!flag){
flag = 1;
pthread_key_create(&key, destructor);
}
}
使用pthread_once:
void destructor(void *);
pthread_once_t initonce = PTHREAD_ONCE_INIT;
pthread_key_t key;
void thread_once(void)
{
pthread_key_create(&key, destructor);
}
int threadfun(void *arg)
{
pthread_once(&initonce, thread_once);
...
}
8.void *pthread_getspecific(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, const void *value);
if(pthread_getspecific(key) == NULL){
printf("需要调用pthread_setspecific");
}
原文:http://blog.csdn.net/tedious/article/details/7776897
阅读(910) | 评论(0) | 转发(0) |