`

线程特定数据

阅读更多
    线程特定数据也称线程私有数据,是存储和查询某个特定线程相关数据的一种机制。在分配线程特定数据之前,需要创建与该数据相关联的键,以用于获取对线程特定数据的访问。使用函数 pthread_key_create 可创建一个键,而对所有的线程,都可以通过 pthread_key_delete 来取消键与线程特定数据值之间的关联关系。
#include <pthread.h>
int pthread_key_create(pthread_key_t *keyp, void (*destructor)(void *));
int pthread_key_delete(pthread_key_t key);
                    /* 两个函数返回值:若成功,返回 0;否则,返回错误编号 */

    创建的键存储在 keyp 指向的内存单元中,这个键可以被进程中的所有线程使用,但每个线程把这个键与不同的线程特定数据地址进行关联。创建新键时,每个线程的数据地址都设为空值。除了创建键以外,pthread_key_create 还可以为该键关联一个可选择的析构函数。当这个线程退出时,如果数据地址已经被置为非空值,那么析构函数就会被调用,它唯一的参数就是该数据地址。当线程调用 pthread_exit 或者返回时,析构函数就会被调用;而当线程取消时,只有在最后的清理处理程序返回后,析构函数才会被调用。线程通常使用 malloc 为线程特定数据分配内存,所以析构函数经常调用 free 函数来释放已分配的内存,以免产生内存泄露。线程可以为线程特定数据分配多个键,每个键都可以关联一个析构函数。线程退出时,线程特定数据的析构函数将按照操作系统实现中定义的顺序被调用。当所有的析构函数都调用完成后,系统会检查是否还有非空的线程特定数据值与键关联。如果有的话,会再次调用析构函数。该过程会一直重复直到线程所有的键都为空线程特定数据值,或者已经做了 PTHREAD_DESTRUCTOR_ITERATIONS 次尝试。
    调用 pthread_key_delete 并不会激活与键关联的析构函数,要释放任何与键关联的线程特定数据值的内存,需要在应用程序中采取额外的步骤。
    为确保分配的键不会因初始化阶段的竞争而发生变动,可以使用函数 pthread_once。键一旦创建以后,就可以通过 pthread_setspecific 函数把键和线程特定数据关联起来,也可通过 pthread_getspecific 函数获得线程特定数据的地址。
#include <pthread.h>
pthread_once_t initflag = PTHREAD_ONCE_INIT;
int pthread_once(pthread_once_t *initflag, void (*initfn)(void));

int pthread_setspecific(pthread_key_t key, const void *value);
                    /* 两个函数返回值:若成功,返回 0;否则,返回错误编号 */
void *pthread_getspecific(pthread_key_t key);
                    /* 返回值:线程特定数据值;若没有值与该键关联,返回 NULL */

    这里的 initflag 必须是一个非本地变量(如全局变量或静态变量),而且必须初始化为 PTHREAD_ONCE_INIT。就算每个线程都调用 pthread_once,系统也能保证初始化例程 initfn 只被调用一次,这可以避免创建键时出现冲突。
    下面给出了 getenv 的一个假设实现,它使用线程特定数据来维护每个线程的数据缓冲区副本,用于存放各自的返回字符串。
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

static pthread_key_t	key;
static pthread_once_t	init_done = PTHREAD_ONCE_INIT;
static pthread_mutex_t	env_mutex = PTHREAD_MUTEX_INITIALIZER;

static void key_init(void){
	pthread_key_create(&key, free);
}

#define MAXSTRINGSZ	4096
extern char **environ;

char *getenv(const char *name){
	pthread_once(&init_done, key_init);
	pthread_mutex_lock(&env_mutex);
	char *env_buf = NULL;
	if((env_buf=(char *)pthread_getspecific(key)) == NULL){
		if((env_buf=malloc(MAXSTRINGSZ)) == NULL){
			pthread_mutex_unlock(&env_mutex);
			return NULL;
		}
		pthread_setspecific(key, env_buf);
	}
	int i = 0, len = strlen(name);
	for(; environ[i] != NULL; i++){
		if(strncmp(name, environ[i], len)==0 && environ[i][len]=='='){
			strncpy(env_buf, &environ[i][len+1], MAXSTRINGSZ-1);
			pthread_mutex_unlock(&env_mutex);
			return env_buf;
		}
	}
	pthread_mutex_unlock(&env_mutex);
	return NULL;
}

    这里使用 pthread_once 来确保只为将要使用的线程特定数据创建一个键。如果 pthread_getspecific 返回的是空指针,就需要先分配内存缓冲区,然后再把键与该内存缓冲区关联起来,否则就使用返回的内存缓冲区。对析构函数,使用 free 来释放之前由 malloc 分配的内存。只有当线程特定数据值为非空时,析构函数才会被调用。
    注意,相较于线程重入中实现的 getenv_r 版本,虽然该版本的 genenv 也使用了互斥量来保证线程安全,但它并不是异步信号安全的。对信号处理程序而言,即使使用递归的互斥量,该版本也不可能是可重入的,因为它调用了本身就不是异步信号安全的 malloc 函数。
分享到:
评论

相关推荐

    线程特定数据linux

    ### 线程特定数据(Thread-Specific Data, TSD)在Linux下的应用 #### 一、背景介绍 在多线程编程环境下,全局变量和静态变量的使用常常会导致不可预知的结果,尤其是在多线程并发访问的情况下。这是因为全局变量...

    易语言线程返回数据的方法

    4. **使用线程句柄**:易语言允许通过线程句柄发送消息,线程执行完毕后,可以通过发送特定消息将数据返回。 5. **回调函数**:线程执行过程中,可以设定一个回调函数,当线程执行完毕,将数据通过回调函数返回。 ...

    Posix Pthread API 总结文档

    pthread_setspecific 函数用于设置线程特定数据,该函数需要两个参数:线程特定数据键和线程特定数据值。 4. 获取线程特定数据 pthread_getspecific 函数用于获取线程特定数据,该函数需要一个参数:线程特定数据...

    多线程编程指南.pdf

    - 删除不再需要的线程特定数据键。 #### 三、设置线程特定数据 **获取线程特定数据** - 如何访问线程特有的数据。 **获取线程标识符** - 获取当前线程的唯一标识符。 **比较线程ID** - 如何比较两个线程ID...

    多线程编程指南 linux

    - **为线程特定数据创建键**:讲解了如何为线程分配特定的数据空间,以便每个线程拥有自己的数据副本。 **3. 设置线程特定数据** - **获取线程特定数据**:说明了如何访问线程内的特定数据。 - **获取线程标识符**...

    winform 多线程处理数据

    为了解决这个问题,我们可以利用C#中的多线程技术来实现后台处理数据,从而保持UI的响应性。本篇将详细讨论如何在WinForm应用中运用多线程处理数据以及异步更新UI。 1. **什么是多线程?** 在计算机科学中,多线程...

    linux多线程手册

    - `pthread_key_delete`用于删除之前创建的线程特定数据键。 ##### 设置线程特定数据 - 使用`pthread_setspecific`函数将特定于线程的数据与键关联起来。 #### 三、获取线程特定数据 - 可以通过`pthread_get...

    linux多线程编程指南

    线程特定数据(TSD)是仅对创建它的线程可见的数据,通过TSD可以避免全局变量的竞态条件问题。 ##### 获取线程特定数据 使用`pthread_getspecific`函数可以获取线程特定数据。 ##### 获取线程标识符 使用`pthread_...

    易语言线程返回数据的方法源码

    在易语言中,可以使用“锁定资源”和“解锁资源”来确保同一时间只有一个线程访问特定的数据,避免数据不一致。 此外,标签“SanYe”可能指的是易语言开发者“三叶草”,他是一个知名的易语言教程作者和社区贡献者...

    Linux多线程编程手册

    线程的分离属性可以指定线程退出时是否自动释放其资源,而线程特定数据允许每个线程拥有自己的数据副本,这些数据对于其他线程是不可见的。 线程属性在pthread中是一个重要的概念,包括线程的分离状态、优先级、栈...

    posix多线程编程

    POSIX线程库(pthread)为Linux下的多线程编程提供了一套完整的工具集,包括线程创建与管理、线程间同步(如互斥锁和条件变量)、线程特定数据、线程取消与终止等高级功能。掌握这些知识不仅能够帮助开发者构建高...

    Solaris多线程编程指南

    - **线程特定数据(TSD)**: 为每个线程分配独立的数据存储空间。 - **创建TSD键**: 使用`pthread_key_create()`函数为TSD创建键。 - **删除线程特定数据键** - **删除TSD键**: 使用`pthread_key_delete()`函数...

    Linux多线程技术

    - **设置线程特定数据**:使用`pthread_setspecific()`函数为指定的键设置特定于当前线程的数据值。 #### 三、高级线程管理 ##### 获取线程标识符 - **线程ID**:每个线程都有一个唯一的标识符,称为线程ID。 - *...

    sun多线程编程

    - **获取线程特定数据**: 通过`pthread_getspecific`函数获取与某个键关联的数据。 - **获取线程标识符**: 使用`pthread_self`函数获取当前线程的标识符。 - **比较线程ID**: 通过直接比较线程标识符来进行。 - **...

    linux多线程编程手册

    - **为线程特定数据创建键**: 创建一个键以存储线程特定的数据。 - **删除线程特定数据键**: 删除不再需要的键。 - **设置线程特定数据**: 将数据关联到特定线程。 **2.2 获取线程特定数据** - **获取线程标识符**...

Global site tag (gtag.js) - Google Analytics