• 多线程私有数据pthread_key_create


    参照:http://blog.csdn.net/xiaohuangcat/article/details/18267561

    在多线程的环境下,进程内的所有线程共享进程的数据空间。因此全局变量为所有线程共享。在程序设计中有时需要保存线程自己的全局变量,这种特殊的变量仅在线程内部有效。

    如常见的errno,它返回标准的错误码。errno不应该是一个局部变量。几乎每个函数都应该可以访问他,但他又不能作为是一个全局变量。否则在一个线程里输出的很可能是另一个线程的

    出错信息,这个问题可以通过创建线程的私有数据(TSD  thread specific data)来解决。在线程内部,私有数据可以被各个函数访问。但他对其他线程是屏蔽的。

    线程私有数据采用了一键多值的技术,即一个键对应多个值。访问数据时都是通过键值来访问,好像是对一个变量进行访问,其实是在访问不同的数据。

    int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));第一个参数为指向一个键值的指针,第二个参数指明了一个destructor函数,

    如果这个参数不为空,那么当每个线程结束时,系统将调用这个函数来释放绑定在这个键上的内存块。

    key一旦被创建,所有线程都可以访问它,但各线程可根据自己的需要往key中填入不同的值,这就相当于提供了一个同名而不同值的全局变量,一键多值。

    一键多值靠的是一个关键数据结构数组即TSD池,创建一个TSD就相当于将结构数组中的某一项设置为“in_use”,并将其索引返回给*key,然后设置清理函数。

    1、创建一个键

    2、为一个键设置线程私有数据

    3、从一个键读取线程私有数据void *pthread_getspecific(pthread_key_t key);

    4、线程退出(退出时,会调用destructor释放分配的缓存,参数是key所关联的数据)

    5、删除一个键

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

    set是把一个变量的地址告诉key,一般放在变量定义之后,get会把这个地址读出来,然后你自己转义成相应的类型再去操作,注意变量的有效期。
    只不过,在不同的线程里可以操作同一个key,他们不会冲突,比如线程a,b,c set同样的key,分别get得到的地址会是之前各自传进去的值。
    这样做的意义在于,可以写一份线程代码,通过key的方式多线程操作不同的数据。

    int pthread_setspecific(pthread_key_t key, const void *value);该函数将value的值(不是内容)与key相关联。用pthread_setspecific为一个键指定新的线程数据时,线程必须先释放原有的线程数据用以回收空间。

    nt pthread_key_delete(pthread_key_t key);用来删除一个键,删除后,键所占用的内存将被释放。注销一个TSD,这个函数并不检查当前是否有线程正使用该TSD,也不会调用清理函数(destr_function),

    而只是将TSD释放以供下一次调用pthread_key_create()使用。需要注意的是,键占用的内存被释放。与该键关联的线程数据所占用的内存并不被释放。因此,线程数据的释放,必须在释放键之前完成。

    简单的示例代码:

    #include <pthread.h>
    #include <stdio.h>
    
    pthread_key_t key;
    pthread_t thid1;
    pthread_t thid2;
    
    void* thread2(void* arg)
    {
        printf("thread:%lu is running
    ", pthread_self());
        
        int key_va = 3 ;
    
        pthread_setspecific(key, (void*)key_va);
        
        printf("thread:%lu return %d
    ", pthread_self(), (int)pthread_getspecific(key));
    }
    
    
    void* thread1(void* arg)
    {
        printf("thread:%lu is running
    ", pthread_self());
        
        int key_va = 5;
        
        pthread_setspecific(key, (void*)key_va);
    
        pthread_create(&thid2, NULL, thread2, NULL);
    
        printf("thread:%lu return %d
    ", pthread_self(), (int)pthread_getspecific(key));
    }
    
    
    int main()
    {
        printf("main thread:%lu is running
    ", pthread_self());
    
        pthread_key_create(&key, NULL);
    
        pthread_create(&thid1, NULL, thread1, NULL);
    
        pthread_join(thid1, NULL);
        pthread_join(thid2, NULL);
    
        int key_va = 1;
        pthread_setspecific(key, (void*)key_va);
        
        printf("thread:%lu return %d
    ", pthread_self(), (int)pthread_getspecific(key));
    
        pthread_key_delete(key);
            
        printf("main thread exit
    ");
        return 0;
    }

     释放空间、每次设置之前判断的代码:

    /*三个线程:主线程,th1,th2各自有自己的私有数据区域
    */
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <pthread.h>
    
    static pthread_key_t str_key;
    //define a static variable that only be allocated once
    static pthread_once_t str_alloc_key_once=PTHREAD_ONCE_INIT;
    static void str_alloc_key();
    static void str_alloc_destroy_accu(void* accu);
    
    char* str_accumulate(const char* s)
    {    char* accu;
        
        pthread_once(&str_alloc_key_once,str_alloc_key);//str_alloc_key()这个函数只调用一次
        accu=(char*)pthread_getspecific(str_key);//取得该线程对应的关键字所关联的私有数据空间首址
        if(accu==NULL)//每个新刚创建的线程这个值一定是NULL(没有指向任何已分配的数据空间)
        {    accu=malloc(1024);//用上面取得的值指向新分配的空间
            if(accu==NULL)    return NULL;
            accu[0]=0;//为后面strcat()作准备
          
            pthread_setspecific(str_key,(void*)accu);//设置该线程对应的关键字关联的私有数据空间
            printf("Thread %lx: allocating buffer at %p
    ",pthread_self(),accu);
         }
         strcat(accu,s);
         return accu;
    }
    //设置私有数据空间的释放内存函数
    static void str_alloc_key()
    {    pthread_key_create(&str_key,str_alloc_destroy_accu);/*创建关键字及其对应的内存释放函数,当进程创建关键字后,这个关键字是NULL。之后每创建一个线程os都会分给一个对应的关键字,关键字关联线程私有数据空间首址,初始化时是NULL*/
        printf("Thread %lx: allocated key %d
    ",pthread_self(),str_key);
    }
    /*线程退出时释放私有数据空间,注意主线程必须调用pthread_exit()(调用exit()不行)才能执行该函数释放accu指向的空间*/
    static void str_alloc_destroy_accu(void* accu)
    {    printf("Thread %lx: freeing buffer at %p
    ",pthread_self(),accu);
        free(accu);
    }
    //线程入口函数
    void* process(void *arg)
    {    char* res;
        res=str_accumulate("Resule of ");
        if(strcmp((char*)arg,"first")==0)
            sleep(3);
        res=str_accumulate((char*)arg);
        res=str_accumulate(" thread");
        printf("Thread %lx: "%s"
    ",pthread_self(),res);
        return NULL;
    }
    //主线程函数
    int main(int argc,char* argv[])
    {    char* res;
        pthread_t th1,th2;
        res=str_accumulate("Result of ");
        pthread_create(&th1,NULL,process,(void*)"first");
        pthread_create(&th2,NULL,process,(void*)"second");
        res=str_accumulate("initial thread");
        printf("Thread %lx: "%s"
    ",pthread_self(),res);
        pthread_join(th1,NULL);
        pthread_join(th2,NULL);
        pthread_exit(0);
    }
  • 相关阅读:
    Vsftpd 3.0.2 正式版发布
    Putdb WebBuilder 6.5 正式版本发布
    SoaBox 1.1.6 GA 发布,SOA 模拟环境
    pynag 0.4.6 发布,Nagios配置和插件管理
    Percona Playback 0.4,MySQL 负荷回放工具
    xombrero 1.3.1 发布,微型 Web 浏览器
    Hypertable 0.9.6.4 发布,分布式数据库
    libmemcached 1.0.11 发布
    CryptoHeaven 3.7 发布,安全邮件解决方案
    Android Activity生命周期
  • 原文地址:https://www.cnblogs.com/zhangxuan/p/6515264.html
Copyright © 2020-2023  润新知