要使用线程特有数据,库函数执行的一般步骤如下:
(1)、函数创建一个键(Key),用以将不同函数使用的线程特有数据项区分开来。
(2)、函数会为每个调用者线程创建线程特有数据块。
(3)、为了保存上一步所分配存储块的地址,函数会使用pthread_setspecific()和pthread_getspecific()。
下面将详细介绍以上步骤中所使用到的函数:
(一)、调用pthread_key_create()函数为线程特有数据创建一个新键,并通过key所指向的缓冲区返回调用者。只要线程终止时与key的关联值部位NULL,Pthread API会自动执行解构函数,并将与key的关联值作为参数传入解构函数中。
#include <pthread.h>
int pthread_key_create(pthread_key_t *key,void(*destructor)(void*));
Return 0 on success,or a positive error number on error.
参数key:因为进程中的所有线程都可以使用返回的键,所以该参数应该指向一个全局变量;
参数destructor:指向一个自定义函数,一般格式如下:
void destructor(void *value)
{
/*Release storage pointed to by 'value'*/
}
(二)、函数pthread_setspecific()和pthread_getspecific()。函数pthread_setspecific()要求Pthread API将value的副本存储到一数据结构中,并将value与调用线程以及key相关联。而pthread_getdpecific()函数的操作步骤与此相反。函数原型如下:
#include <pthread.h>
int pthread_setspecific(pthread_key_t key, const void *value);
Return 0 on success,or a positive error number on error;
int pthread_getspecific(pthread_key_t key)
Return Pointer,or NULL if no thread-specific data isassociated with key
函数pthread_setspecific()的参数value通常是一个指针,指向由调用者分配的一块内存。当线程终止时,会将该指针作为参数传递给与key对应的解构函数中。
例程程序如下:
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <tlpi_hdr.h>
static pthread_once_t once = PTHREAD_ONCE_INIT;
static pthread_key_t strerrorkey;
#define MAX_ERROR_LEN 256
static void destructor(void *buf)
{
free(buf);
}
static void creatkey(void)
{
int s;
s = pthread_key_create(&strerrorkey,destructor);
if(s!=0)
errExitEN(s,"pthread_key_create");
}
char * strerror( int err)
{
int s;
char *buf;
s = pthread_once(&once,createkey);
if(s!=0)
errExitEN(s,"pthread_once");
buf = pthread_getspecific(strerrorkey)
if(buf == NULL)
{
buf = malloc(MAX_ERROR_LEN);
if(buf == NULL)
errExit("malloc");
s = pthread_setspecific(strerrorkey,buf);
if(s!=0)
errExitEN(s,"pthread_setspecific");
}
if(err<0||err>= _sys_nerr || _sys_errlist[err] == NULL)
{
snprintf(buf,MAX_ERROR_LEN,"Unknown error %d",err);
}
return buf;
}