Linux多线程基础学习(八)私有数据

在进程内的所有线程共享相同的地址空间,任何声明为静态或外部的变量,或在进程堆声明的变量,都可以被进程所有的线程读写。那怎样才能使线程序拥有自己的私有数据呢。

posix提供了一种方法,创建线程键。

1.为什么需要线程私有数据:

      原因一:有时候需要维护基于每个线程的数据,用线程ID作为索引。因为线程ID不能保证是小而连续的整数,所以不能简单的分配一个线程数据数组,用线程ID作为数组的索引。即使线程ID确实是小而连续的整数,可能还希望有一些额外的保护,以防止某个线程的数据和其它线程的数据相混淆。

      原因二:可以让基于进程的接口适应多线程环境,比如errno,线程出现以前errno被定义成进程环境中全局可访问的整数,线程出现以后,为了让线程也能使用那些原本基于进程的系统调用和库例程,errno被重新定义成线程私有数据。

2.为线程私有数据用法:

 

在使用私有数据之前,你首先要创建一个与私有数据相关的键,要来获取对私有数据的访问权限。这个键的类型是pthread_key_t

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

创建的键放在key指向的内存单元,destructor是与键相关的析构函数。当线程调用pthread_exit或者使用return返回,析构函数就会被调用。当析构函数调用的时候,它只有一个参数,这个参数是与key关联的那个数据的地址(也就是你的私有数据啦),因此你可以在析构函数中将这个数据销毁。

键使用完之后也可以销毁,当键销毁之后,与它关联的数据并没有销毁哦

int pthread_key_delete(pthread_key_t key);

 

有了键之后,你就可以将私有数据和键关联起来,这样就就可以通过键来找到数据。所有的线程都可以访问这个键,但他们可以为键关联不同的数据。(这岂不是一个名字一样,而值却不同的全局变量么)

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

将私有数据与key关联

void *pthread_getspecific(pthread_key_tkey);

获取私有数据的地址,如果没有数据与key关联,那么返回空

注意点:

      在分配(malloc/new)线程私有数据之前,需要创建和线程私有数据相关联的键(key),这个键的功能是获得对线程私有数据的访问权。

      如果创建一个线程私有数据键,必须保证Pthread_key_create对于每个Pthread_key_t变量仅仅被调用一次,因为如果一个键被创建两次,其实是在创建两个不同的键,第二个键将覆盖第一个键,第一个键以及任何线程可能为其关联的线程私有数据值将丢失。

      创建新键时,每个线程的数据地址设为NULL。

      需要确保分配的键不会由于初始化阶段的竞争而发生变动。(使用pthread_once避免)

 

      线程退出时,线程私有数据的析构函数将按照OS实现定义的顺序被调用。析构函数可能调用另外一个函数,而该函数可能创建新的线程私有数据而且把这个线程私有数据和当前的键关联起来。当所有的析构函数都调用完成以后,系统会检查是否有非NULL的线程私有数据值与键关联,如果有的话,再次调用析构函数,这个过程一直重复到线程所有的键都为NULL值线程私有数据,或者已经做了PTHREAD_DESTRUCTOR_ITERATIONS中定义的最大次数的尝试.

 

3. 例程:


/*============================================================================
// Name        : thread_privateData.cpp
// Author      : Ryan
// Version     :
// Copyright   : zjut
// Description : 测试线程私有数据
//============================================================================*/

#include 
#include 
#include 
//#include "../errors.h"
using namespace std;

struct private_tag{
        pthread_t thread_id;
        char *thread_name;
};

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_key_t key;
int count = 0;

void *key_get(void *arg)
{
        void *value = NULL;
        int status;

        value = pthread_getspecific(key);
        if(value == NULL){

                value = new private_tag;//创建数据的动态内存
                //初始化数据
                ((private_tag *)value)->thread_id = pthread_self();
                ((private_tag *)value)->thread_name = (char *)arg;

                if(value == NULL){
                        cout<<"new"<thread_id<<" thread_name:"<thread_name<thread_id)<<" key: "<< pthread_getspecific(key)<thread_name);
//        free(arg);
        delete (private_tag*)arg;

        status = pthread_mutex_lock(&mutex);//lock
        if(status != 0){
        	cout<<"mutex lock erro"<thread_id = pthread_self();
//        value->thread_name = "main thread";
        char *thread_1 = "thread 1";
        char *thread_2 = "thread 2";

        status = pthread_create(&thread1, NULL, thread_routine, thread_1);
        if(status != 0){
        	cout<<"create thread1"<


4 结果:

Linux多线程基础学习(八)私有数据_第1张图片

你可能感兴趣的:(多线程)