美文网首页
线程特定数据

线程特定数据

作者: Junior888 | 来源:发表于2018-08-18 23:01 被阅读0次

    Linux多线程实践(4) --线程特定数据

    1. 线程特定数据是什么?

    单线程 C 程序有两类基本数据:局部数据和全局数据。对于多线程 C 程序,添加了第三类
    数据:线程特定数据。线程特定数据与全局数据非常相似,区别在于前者为线程专有。

    在单线程程序中,我们经常要用到"全局变量"以实现多个函数间共享数据, 然而在多线程环境下,由于数据空间是共享的,因此全局变量也为所有线程所共有。但有时应用程序设计中有必要提供线程私有的全局变量,仅在某个线程中有效,但却可以跨多个函数访问。POSIX线程库通过维护一定的数据结构来解决这个问题,这个些数据称为(Thread-specific-data或 TSD)。

    线程特定数据基于每线程进行维护。TSD(特定于线程的数据)是定义和引用线程专用数
    据的唯一方法。每个线程特定数据项都与一个作用于进程内所有线程的键关联。通过使用
    key,线程可以访问基于每线程进行维护的指针 (void *)。

    线程特定数据

    从上图可知:当调用pthread_key_create 后会产生一个所有线程都可见的线程特定数据(TSD)的键值(如上图中所有的线程都会得到一个pkey[1]的值), 但是这个键所指向的真实数据却是不同的,虽然都是pkey[1], 但是他们并不是指向同一块内存,而是指向了只属于自己的实际数据, 因此, 如果线程0更改了pkey[1]所指向的数据, 而并不能够影像到线程n;

    在线程调用pthread_setspecific后会将每个线程的特定数据与thread_key_t绑定起来,虽然只有一个pthread_key_t,但每个线程的特定数据是独立的内存空间,当线程退出时会执行destructor 函数。

    2. 常用函数有哪些?

    int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *));
    //分配用于标识进程中线程特定数据的键。键对进程中的所有线程来说是全局的。
    
    int pthread_key_delete(pthread_key_t key);
    //删除线程特定数据键
     
    int pthread_setspecific(pthread_key_t key, const void *pointer);
    //设置线程特定数据
    
    void * pthread_getspecific(pthread_key_t key);
     //获取线程特定数据
    

    3. 示例

    /** 示例1: 设置/获取线程特定数据
    在两个线程中分别设置/获取线程特定数据, 查看两个线程中的数据是否是一样的(肯定是不一样的O(∩_∩)O~)
    **/
    pthread_key_t key;
    typedef struct Tsd
    {
        pthread_t tid;
        char *str;
    } tsd_t;
    //用来销毁每个线程所指向的实际数据
    void destructor_function(void *value)
    {
        free(value);
        cout << "destructor ..." << endl;
    }
     
    void *thread_routine(void *args)
    {
        //设置线程特定数据
        tsd_t *value = (tsd_t *)malloc(sizeof(tsd_t));
        value->tid = pthread_self();
        value->str = (char *)args;
        pthread_setspecific(key, value);
        printf("%s setspecific, address: %p\n", (char *)args, value);
     
        //获取线程特定数据
        value = (tsd_t *)pthread_getspecific(key);
        printf("tid: 0x%x, str = %s\n", (unsigned int)value->tid, value->str);
        sleep(2);
     
        //再次获取线程特定数据
        value = (tsd_t *)pthread_getspecific(key);
        printf("tid: 0x%x, str = %s\n", (unsigned int)value->tid, value->str);
     
        pthread_exit(NULL);
    }
     
    int main()
    {
        //这样每个线程当中都会有一个key可用了,
        //但是每个key所绑定的实际区域需要每个线程自己指定
        pthread_key_create(&key, destructor_function);
     
        pthread_t tid1, tid2;
        pthread_create(&tid1, NULL, thread_routine, (void *)"thread1");
        pthread_create(&tid2, NULL, thread_routine, (void *)"thread2");
     
        pthread_join(tid1, NULL);
        pthread_join(tid2, NULL);
        pthread_key_delete(key);
     
        return 0;
    }
    
    /** 示例2:运用pthread_once, 让key只初始化一次
    注意: 将对key的初始化放入到init_routine中
    **/
    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<pthread.h>
    
    pthread_key_t key;
    pthread_once_t once_control = PTHREAD_ONCE_INIT;
    typedef struct Tsd
    {
        pthread_t tid;
        char *str;
    } tsd_t;
     
    //线程特定数据销毁函数,
    //用来销毁每个线程所指向的实际数据
    void destructor_function(void *value)
    {
        free(value);
        printf("destructor ...\n");
    }
     
    //初始化函数, 将对key的初始化放入该函数中,
    //可以保证inti_routine函数只运行一次
    void init_routine()
    {
        pthread_key_create(&key, destructor_function);
        printf("init...\n");
    }
     
    void *thread_routine(void *args)
    {
        pthread_once(&once_control, init_routine);
     
        //设置线程特定数据
        tsd_t *value = (tsd_t *)malloc(sizeof(tsd_t));
        value->tid = pthread_self();
        value->str = (char *)args;
        pthread_setspecific(key, value);
        printf("%s setspecific, address: %p\n", (char *)args, value);
     
        //获取线程特定数据
        value = (tsd_t *)pthread_getspecific(key);
        printf("tid: 0x%x, str = %s\n", (unsigned int)value->tid, value->str);
        sleep(2);
     
        //再次获取线程特定数据
        value = (tsd_t *)pthread_getspecific(key);
        printf("tid: 0x%x, str = %s\n", (unsigned int)value->tid, value->str);
     
        pthread_exit(NULL);
    }
     
    int main()
    {
        pthread_t tid1, tid2;
        pthread_create(&tid1, NULL, thread_routine, (void *)"thread1");
        pthread_create(&tid2, NULL, thread_routine, (void *)"thread2");
     
        pthread_join(tid1, NULL);
        pthread_join(tid2, NULL);
        pthread_key_delete(key);
     
        return 0;
    }
    

    执行结果如下所示:

    junior@ubuntu:~/thread$ ./thread_spec 
    init...
    thread2 setspecific, address: 0x7f2584000f30
    tid: 0x8971a700, str = thread2
    thread1 setspecific, address: 0x7f257c000b20
    tid: 0x89f1b700, str = thread1
    tid: 0x8971a700, str = thread2
    destructor ...
    tid: 0x89f1b700, str = thread1
    destructor ...
    

    相关文章

      网友评论

          本文标题:线程特定数据

          本文链接:https://www.haomeiwen.com/subject/cufxiftx.html