线程特定数据(笔记)

概述:

    线程特定数据,也称为线程私有数据,是存储和查询某个特定数据相关数据的一种机制。

    在单线程程序中,我们经常要用到“全局变量”以实现多个函数间共享数据。

    在多线程环境下,由于数据空间是共享的,因此全局变量也为所有所有线程所共有。

    但有时应用程序设计中有必要提供线程私有的全局变量,仅在某个线程中有效,但却可以跨多个函数访问。

    POSIX线程库通过维护一定的数据结构来解决这个问题,这些数据被称为线程特定数据(Thread-specific Data,或TSD)。    

相关函数:

    在分配线程特定数据之前,需要创建与该数据关联的键。这个键将用于获取对线程特定数据的访问。使用pthread_key_create函数创建一个键。

  int pthread_key_create(pthread_key_t *key, void (*destr_function) (void*));

    创建的键存储在pkey指向的内存单元中,这个键可以被进程中的所有线程使用,但每个线程与不同的线程特定数据地址相关联。创建新键时,每个线程的数据地址设为空值。

    除了创建键以外,pthread_key_create可以为该键关联一个可选择的析构函数。当这个线程退出时,如果数据地址已经被置为非空值,那么析构函数就会被调用,它唯一的参数就是该数据地址。如果传入的析构函数为空,就表明没有析构函数与这个键关联。

    线程通常使用malloc为线程特定数据分配内存。析构函数通常释放已分配的内存。

    对所有的线程,我们都可以通过调用pthread_key_delete函数来取消键与线程特定数据值之间的联系。

   int pthread_key_delete(pthread_key_t key);

    有些线程可能看到一个键值,而其他的线程看到的可能是另一个不同的键值,这取决于系统是如何调度线程的,解决这种竞争的办法是使用pthread_once函数 。

       pthread_once_t once_control = PTHREAD_ONCE_INIT;

       int  pthread_once(pthread_once_t  *once_control,  void  (*init_routine)
       (void));

    once_control必须是一个非本地变量(如全局变量或静态变量),而且必须初始化为PTHREAD_ONCE_INIT。如果每个线程都调用pthread_once,系统就能保证初始化once_control只被调用一次,即系统首次调用pthread_once时。

    

    键一旦创建以后,就可以通过调用pthread_setspecific函数把键和线程特定数据关联起来。可以通过pthread_getspecific获得线程特定数据的地址。  

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

       void * pthread_getspecific(pthread_key_t key);

    如果没有线程特定数据值与键关联,pthread_getspecific将返回一个空指针,我们可以用这个空指针确定是否需要调用pthread_setspecific。

注:参考UNIX高级环境编程(第三版)

测试代码:

#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define ERR_EXIT(m)			\
	do				\
	{				\
		perror(m);		\
		exit(EXIT_FAILURE);     \
	}while(0);			\

//自定义线程数据
typedef struct tid
{
	pthread_t tid;
	char *str;
}tsd_t;

pthread_key_t key_tsd;
pthread_once_t once_control = PTHREAD_ONCE_INIT;


void destory_routine(void *value)
{
	printf("destory...\n");
	free(value);

}

void once_routine(void)
{
	pthread_key_create(&key_tsd, destory_routine);
	printf("key init...\n");
	
}

void *thread_routine(void *arg)
{
	pthread_once(&once_control,once_routine) ;
	tsd_t *value = (tsd_t*)malloc(sizeof(tsd_t));
	value->tid = pthread_self();
	value->str = (char*)arg;
	//设置线程特定数据
	pthread_setspecific(key_tsd, value);
	printf("%s setspecific %p\n",(char*)arg, value);

   	value = (tsd_t*)pthread_getspecific(key_tsd);
	printf("tid=0x%x str=%s\n",(int)value->tid, value->str);
	sleep(2);
   	value = (tsd_t*)pthread_getspecific(key_tsd);
	printf("tid=0x%x str=%s\n",(int)value->tid, value->str);
	sleep(2);
	return NULL;
}

int main(void)
{
	//pthread_key_create(&key_tsd, destory_routine);

	pthread_t tid1;
	pthread_t tid2;
	pthread_create(&tid1, NULL, thread_routine, "thread1");
	pthread_create(&tid2, NULL, thread_routine, "thread2");

	pthread_join(tid1, NULL);
	pthread_join(tid1, NULL);
	return 0;
}

运行截图:


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值