Chinaunix首页 | 论坛 | 博客
  • 博客访问: 494181
  • 博文数量: 133
  • 博客积分: 1235
  • 博客等级: 少尉
  • 技术积分: 1201
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-08 19:59
文章分类

全部博文(133)

文章存档

2023年(12)

2022年(3)

2018年(2)

2017年(4)

2016年(4)

2015年(42)

2014年(1)

2013年(12)

2012年(16)

2011年(36)

2010年(1)

分类: LINUX

2011-12-12 17:31:50

 C 程序有两类基本数据:局部数据和全局数据。

对于多线程 C 程序,添加了第三类数据:线程特定数据。线程特定数据与全局数据非常相似,区别在于前者为线程专有。
线程特定数据基于每线程进行维护。TSD(特定于线程的数据)是定义和引用线程专用数据的唯一方法。每个线程特定数据项都与一个作用于进程内所有线程的键关联。通过使用 key,线程可以访问基于每线程进行维护的指针

int pthread_key_create(pthread_key_t *key, void (*destructor) (void *))

pthread_key_t key;

int ret;

/* key create without destructor */

ret = pthread_key_create(&key, NULL);

/* key create with destructor */

ret = pthread_key_create(&key, destructor);

可以使用 pthread_key_create函数分配用于标识进程中线程特定数据的键。键对进程中的所有线程来说是全局的。创建线程特定数据时,所有线程最初都具有与该键关联的 NULL 值。
创建键之后,每个线程都会将一个值绑定到该键。这些值特定于线程并且针对每个线程单独维护。如果创建该键时指定了 destructor 函数,则该线程终止时,系统会解除针对每线程的绑定。
使用可选的析构函数 destructor 可以释放过时的存储。如果某个键具有非 NULL destructor 函数,而线程具有一个与该键关联的非 NULL 值,则该线程退出时,系统将使用当前的相关值调用 destructor 函数。destructor 函数的调用顺序不确定。
pthread_key_create 返回值pthread_key_create() 在成功完成之后返回零。其他任何返回值都表示出现了错误。如果出现以下任一情况,pthread_key_create() 将失败并返回相应的值。
EAGAIN
描述: key 名称空间已经用完。
ENOMEM
描述: 此进程中虚拟内存不足,无法创建新键。
删除线程特定数据键使用 pthread_key_delete函数 可以销毁现有线程特定数据键。由于键已经无效,因此将释放与该键关联的所有内存。引用无效键将返回错误。

 语法int pthread_key_delete(pthread_key_t key);

#include

pthread_key_t key;

int ret;

/* key previously created */

ret = pthread_key_delete(key);

如果已删除键,则使用调用 pthread_setspecific()pthread_getspecific() 引用该键时,生成的结果将是不确定的。
程序员在调用删除函数之前必须释放所有线程特定资源。删除函数不会调用任何析构函数。反复调用 pthread_key_create()pthread_key_delete() 可能会产生问题。

对于每个所需的键,应当只调用 pthread_key_create() 一次。
pthread_key_delete() 在成功完成之后返回零。其他任何返回值都表示出现了错误。如果出现以下情况,pthread_key_delete() 将失败并返回相应的值。
EINVAL
描述: key 的值无效。
设置线程特定数据使用 pthread_setspecific() 可以为指定线程特定数据键设置线程特定绑定。 
语法

int pthread_setspecific(pthread_key_t key, const void *value);

#include

pthread_key_t key;

void *value;

int ret;

/* key previously created */

ret = pthread_setspecific(key, value);

 返回值pthread_setspecific() 在成功完成之后返回零。其他任何返回值都表示出现了错误。如果出现以下任一情况,pthread_setspecific() 将失败并返回相应的值。
ENOMEM
描述: 虚拟内存不足。
EINVAL
描述: key 无效。

注意:设置新绑定时,pthread_setspecific() 不会释放其存储空间。必须释放现有绑定,否则会出现内存泄漏。

获取线程特定数据请使用 pthread_getspecific 获取调用线程的绑定,并将该绑定存储在 value 指向的位置中。
语法 void *pthread_getspecific(pthread_key_t key);

#include

pthread_key_t key;

void *value;

/* key previously created */

value = pthread_getspecific(key);

返回值pthread_getspecific 不返回任何错误。

示例

#include
#include
#include

#define LEN 100
pthread_key_t key;
void A(char* s)
{
    char* p = (char*)pthread_getspecific(key);
    strcpy(p,s);
}
void B()
{
    char* p = (char*)pthread_getspecific(key);
    printf("%s\n",p);
}
void destructor(void* ptr)
{
    // sleep(1);
    printf("...%x\n",(char*)ptr);
    free(ptr);
    printf("Memorey free\n");
}
void createkey(void)
{
    pthread_key_create(&key,destructor);  //创建键.
}
void* threadFun1(void* arg)
{
    static pthread_once_t once = PTHREAD_ONCE_INIT;
    pthread_once(&once,createkey);   //为了只创建一次这个键.第一次调用pthread_once时它执行这个函数creatkey,以后的调用将忽略
    char* p = (char*)malloc(LEN);
    printf("%x\n",p);
    pthread_setspecific(key,p);
    //sleep(2);

    A("Thread1");

    B();
}
void* threadFun2(void* arg)
{
    static pthread_once_t once = PTHREAD_ONCE_INIT;
    pthread_once(&once,createkey);
    char* p = (char*)malloc(LEN);
    printf("%x\n",p);
    pthread_setspecific(key,p);
  //  A("Thread1");
   A("Thread2...");
   B();
}
int main()
{
    pthread_t tid1,tid2;
//   pthread_key_create(&key,destructor);
    if(pthread_create(&tid1, NULL, &threadFun1, NULL) != 0)
       printf("create thread1 fail\n");
    if(pthread_create(&tid2, NULL, &threadFun2, NULL) != 0)
       printf("create thread2 fail\n");
  //  B();
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    return 1;
}
注意:当用pthread_setspecific为一个键指定新的特定线程数据时,必须自己释放原有的特定线程数据以回收空间. pthread_key_delete用来删除一个键,这个键占用的内存将释放,但它只释放键占用的内存,并不释放键关联的特定线程数据所占用的内存资源,而且它也不会触发函数pthread_key_create中注册的destructor函数.特定线程数据的释放必须在释放键之前完成.

阅读(1373) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~