精华内容
下载资源
问答
  • 最近阅读一份linux的线程代码时,看到了一套函数,pthread_getspecificpthread_setspecific函。光从名字上,完全无法理解出他们到底是干啥的,结合代码来看,也不是很清楚。于是就去百度。可是,百度来百度去,...

    最近阅读一份linux的线程代码时,看到了一套函数,pthread_getspecific/pthread_setspecific。光从名字上,完全无法理解出他们到底是干啥的,结合代码来看,也不是很清楚。于是就去百度。可是,百度来百度去,CSDN来CSDN去,反反复复找了不少资料,却始终没能完全理解透彻。感觉大家都是从同一份博客里抄来抄去的,甚至连其中的错误都照抄了,不但没能解答我的疑惑,反而还带来了其他的问题。

    题外话一:这里实在想吐槽一下百度的学术资料搜索能力,跟人家google比,实在是差太多了,找半天都找不到什么有用的资料。广告搜索能力倒是挺强,各种推广广告一堆堆的跳出来,而且是在最显眼的地方。为什么不能把广告的搜索能力移植到学术资料的搜索上来呢?

    题外话二:这里还想吐槽一下部分CSDN的网友,看到别人的博客,自己也不验证验证,消化消化,就直接复制黏贴过来,关键也不注明一下是不是转载的,更不用说贴上源地址了。我找资料时,一个关键词输进去,链接确实能跳出来不少,但是点进去发现TM全是同一篇文章,只是由不同的博主转来转去的,绝大部分人甚至连原博文的错误都一并转载了,实在是哭笑不得。

    不管如何,自己的疑问还是要搞清楚的。于是继续查阅资料,并对这两个函数的用法进行总结和实践,总算是基本搞清了。下面对我自己的心得进行一下总结,希望能给其他小伙伴提供一下借鉴。

    一、技术原理

    首先要交代一下,pthread_getspecific/pthread_setspecific这两个函数,其实是属于线程数据存储机制【也叫线程私有数据,英文名Thread Specific Data】的一部分。因此,要先引入线程存储机制这个大话题,才能进行比较全面而清晰的了解。

    大家都知道,在多线程程序中,一个模块里的全局变量,对于该模块的所有线程都是可见的,也就是说全局共享的,所有线程都可以使用它,可以随时改变它的值,这显然是不安全的,会带来一些风险。那么有没有什么办法能改善这个问题呢?在强大的linux系统下,一切皆有可能!这就到了线程存储机制隆重登场的时候了!应用了线程存储机制之后,这个变量表面上看起来还是一个全局变量,所有线程都可以使用它,而它的值在每一个线程中又是单独隔离的,彼此之间不会互相影响。A线程对该变量的值进行修改之后,相应的变化只会在A线程中体现,其他的线程中去查询该变量时,得到的依然是本线程中的值,跟A线程改动的值无关。

    比如linux系统下常见的errno,它返回标准的错误码。errno肯定不是一个局部变量,因为几乎每个函数都可以访问他。但它又不能是一个简单的全局变量,否则在一个线程里输出的很可能是另一个线程的出错信息。因此,必须借助于创建线程的私有数据来解决。线程私有数据采用一键多值的技术,即一个键对应多个值。访问数据时都是通过键值来访问,表面上看上去好像是对同一个变量进行访问,但是实际上访问的是不同的数据空间。

    线程存储机制的具体用法如下:

    1. 首先要定义一个类型为pthread_key_t类型的全局变量。
    2. 调用pthread_key_create()来创建该变量。该函数有两个参数,第一个参数就是上面声明的pthread_key_t变量,第二个参数是一个清理函数,用来在线程释放该线程存储的时候被调用。该函数指针可以设成NULL,这样系统将调用默认的清理函数。该函数调用成功时返回0,返回其他任何值都表示出现了错误。
    3. 当线程中需要存储特殊值的时候,可以调用pthread_setspcific()。该函数有两个参数,第一个为前面声明的pthread_key_t变量,第二个为void*变量,这样你可以存储任何类型的值。
    4. 如果需要取出所存储的值,调用pthread_getspecific()。该函数的参数为前面提到的pthread_key_t变量,该函数返回void *类型的值。
    5. 注销使用pthread_key_delete()函数,该函数并不检查当前是否有线程正在使用,也不会调用清理函数,而只是释放以供下一次调用pthread_key_create()使用。

    下面是前面提到的函数原型:

    #include <pthread.h>
    
    int pthread_key_create(pthread_key_t *key, void (*destructor)(void *));
    int pthread_key_delete(pthread_key_t *key);
    int pthread_setspecific(pthread_key_t key, const void *value);
    void *pthread_getspecific(pthread_key_t key);
    

    二、实例解析

    下面的代码是从网上摘录过来,内容很简单,就是用来验证这两个函数的使用。

    新建一个模块命名为test.c,输入以下内容:

    #include <stdio.h>
    #include <pthread.h>
    #include <string.h>
    
    static pthread_key_t p_key;
     
    void *thread_func(void *args)
    {
        int *tmp1, *tmp2;
        
        /* 注意:这里初始化私有键值时使用的特征值,是该线程创建时传入的特征值a/b */
        pthread_setspecific(p_key, args);                                          /* 初始化本线程的私有键值 */
        printf("in thread %d. init specific_data to %d\n", *(int *)args, *(int *)args);
        
        tmp1 = (int *)pthread_getspecific(p_key);                                  /* 获取私有键值的内容 */
        printf("get specific_data %d\n", *tmp1);
     
        *tmp1 = (*tmp1) * 100;                                                     /* 修改私有键值的内容 */
        printf("change specific_data to %d\n", *tmp1);
    
        tmp2 = (int *)pthread_getspecific(p_key);                                  /* 重新获取本线程的私有键值 */
        printf("get specific_data %d\n", *tmp2);
     
        return (void *)0;
    }
    
    int main()
    {
        int a = 1;
        int b = 2;
        pthread_t pa, pb;
        
        printf("at first: a = %d. b = %d\n", a, b);
    
        pthread_key_create(&p_key, NULL);                                          /* 首先创建私有数据键值 */
        
        pthread_create(&pa, NULL, thread_func, &a);                                /* 创建线程1 */
        pthread_create(&pb, NULL, thread_func, &b);                                /* 创建线程2 */
    
        pthread_join(pa, NULL);
        pthread_join(pb, NULL);
        
        /* 解释下pthread_join函数:它的目的是使一个线程等待另一个线程结束 */
        /* 代码中如果没有pthread_join主线程会很快结束从而使整个进程结束,创建的线程根本来不及执行 */
        /* 加入pthread_join后,主线程会一直等待直到等待的线程结束自己才结束,使创建的线程有机会执行 */
        
        printf("at last: a = %d. b = %d\n", a, b);
    
        return 0;
    }
    

    编译链接并运行,可以看到输出信息如下:

    leon@Ubuntu:~/test$ gcc test.c -lpthread -o test
    leon@Ubuntu:~/test$ ./test
    at first: a = 1. b = 2
    in thread 1. init specific_data to 1
    get specific_data 1
    change specific_data to 100
    get specific_data 100
    in thread 2. init specific_data to 2
    get specific_data 2
    change specific_data to 200
    get specific_data 200
    at last: a = 100. b = 200
    

    可以看出,两个线程中分别对私有键值进行了初始化、读取、修改、读取的过程,所得到的键值按照预期的规律发生了变化,同时又彼此独立互不影响。

    三、补充说明

    这里要说明一下,不少CSDN网友所转载的文章里,都对上面的代码使用“gcc -lpthread test.c -o test”这样的语句进行编译链接,但是却没人发现这里面的问题!!

    大家可以自己去编译一下试试看,如果你输入“gcc -lpthread test.c -o test”,绝对是编译不过的,系统会提示:

    /tmp/ccSkayWg.o:在函数‘test’中:
    thread_spc.c:(.text+0x11):对‘pthread_getspecific’未定义的引用
    /tmp/ccSkayWg.o:在函数‘thread_func’中:
    thread_spc.c:(.text+0x54):对‘pthread_setspecific’未定义的引用
    thread_spc.c:(.text+0x61):对‘pthread_getspecific’未定义的引用
    /tmp/ccSkayWg.o:在函数‘main’中:
    thread_spc.c:(.text+0xd0):对‘pthread_key_create’未定义的引用
    thread_spc.c:(.text+0xed):对‘pthread_create’未定义的引用
    thread_spc.c:(.text+0x10a):对‘pthread_create’未定义的引用
    thread_spc.c:(.text+0x11b):对‘pthread_join’未定义的引用
    thread_spc.c:(.text+0x12c):对‘pthread_join’未定义的引用
    

    这是因为gcc依赖顺序的问题导致的。就是gcc编译的时候,各个文件的依赖顺序是有讲究的。如果文件a依赖于文件b,那么编译的时候必须把a放前面,b放后面。

    例如,在main.c中使用了pthread库相关函数,那么编译的时候必须是main.c在前,-lpthread在后:

    gcc main.c -lpthread -o a.out
    

    所以,上面出现问题的原因就是引入库的顺序出了问题,不能放在前面,得放到后面去:

    gcc test.c -lpthread -o test
    
    展开全文
  • 文章目录1.pthread_getspecificpthread_setspecific简介2.pthread_getspecificpthread_setspecific使用eg13.pthread_getspecificpthread_setspecific使用eg 1.pthread_getspecificpthread_setspecific简介 ...

    1.pthread_getspecific和pthread_setspecific简介

    函数 pthread_setspecific() 将 pointer 的值 (不是锁指的内容) 与key 相关联。
    函数 pthread_getspecific() 将与 key 相关联的数据读出来。返回的数据类型都是 void *,因此可以指向任何类型的数据。
    
    在多线程程序中,经常要用全局变量来实现多个函数间的数据共享。由于数据空间是共享的,因此全局变量也为所有线程所共有。
    但有时应用程序设计中必要提供线程私有的全局变量,这个变量仅在线程中有效,但却可以跨过多个函数访问。
    
    比如在程序里可能需要每个线程维护一个链表,而会使用相同的函数来操作这个链表,最简单的方法就是使用同名而不
    同变量地址的线程相关数据结构。这样的数据结构可以由 Posix 线程库维护,成为线程私有数据 (Thread-specific Data,或称为 TSD)
    pthread_getpecific和pthread_setspecific提供了在同一个线程中不同函数间共享数据即线程存储的一种方法。具体用法为:
    (1)调用pthread_key_create()来创建一个类型为pthread_key_t类型的变量
    
    该函数有两个参数,第一个参数就是声明的pthread_key_t变量;
    第二个参数是一个清理函数,用来在线程释放该线程存储的时候被调用。
    该函数指针可以设成NULL,这样系统将调用默认的清理函数。
    
    (2)调用pthread_setspcific()
    
    当线程中需要存储特殊值的时候调用该函数,该函数有两个参数,
    第一个为前面声明的pthread_key_t变量,
    第二个为void*变量,用来存储任何类型的值。
    
    (3)如果需要取出所存储的值,调用pthread_getspecific()
    
    该函数的参数为前面提到的pthread_key_t变量,该函数返回void*类型的值。
    

    2.pthread_getspecific和pthread_setspecific使用eg1

    #include<stdio.h>
    #include<pthread.h>
    #include<string.h>
    pthread_key_t p_key;
     
    void func1()
    {
            int *tmp = (int*)pthread_getspecific(p_key);//同一线程内的各个函数间共享数据。
            printf("%d is runing in %s\n",*tmp,__func__);
     
    }
    void *thread_func(void *args)
    {
     
            pthread_setspecific(p_key,args);
     
            int *tmp = (int*)pthread_getspecific(p_key);//获得线程的私有空间
            printf("%d is runing in %s\n",*tmp,__func__);
     
            *tmp = (*tmp)*100;//修改私有变量的值
     
            func1();
     
            return (void*)0;
    }
    int main()
    {
            pthread_t pa, pb;
            int a=1;
            int b=2;
            pthread_key_create(&p_key,NULL);
            pthread_create(&pa, NULL,thread_func,&a);
            pthread_create(&pb, NULL,thread_func,&b);
            pthread_join(pa, NULL);
            pthread_join(pb, NULL);
            return 0;
    }
    
    
    #gcc thread.c -o test -lpthread
    #./test
    
    1 is runing in thread_func
    100 is runing in func1
    2 is runing in thread_func
    200 is runing in func1
    

    3.pthread_getspecific和pthread_setspecific使用eg2

    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    pthread_key_t key;
    struct test_struct {
        int i;
        float k;
    };
    void *child1 (void *arg)
    {
        struct test_struct struct_data;
        struct_data.i = 10;
        struct_data.k = 3.1415;
        pthread_setspecific (key, &struct_data);
        printf ("结构体struct_data的地址为 0x%p\n", &(struct_data));
        printf ("child1 中 pthread_getspecific(key)返回的指针为:0x%p\n", (struct test_struct *)pthread_getspecific(key));
        printf ("利用 pthread_getspecific(key)打印 child1 线程中与key关联的结构体中成员值:\nstruct_data.i:%d\nstruct_data.k:
    %f\n", ((struct test_struct *)pthread_getspecific (key))->i, ((struct test_struct *)pthread_getspecific(key))->k);
        printf ("------------------------------------------------------\n");
    }
    void *child2 (void *arg)
    {
        int temp = 20;
        sleep (2);
        printf ("child2 中变量 temp 的地址为 0x%p\n",  &temp);
        pthread_setspecific (key, &temp);
        printf ("child2 中 pthread_getspecific(key)返回的指针为:0x%p\n", (int *)pthread_getspecific(key));
        printf ("利用 pthread_getspecific(key)打印 child2 线程中与key关联的整型变量temp 值:%d\n", *((int *)pthread_getspecific(key)));
    }
    int main (void)
    {
        pthread_t tid1, tid2;
        pthread_key_create (&key, NULL);
        pthread_create (&tid1, NULL, (void *)child1, NULL);
        pthread_create (&tid2, NULL, (void *)child2, NULL);
        pthread_join (tid1, NULL);
        pthread_join (tid2, NULL);
        pthread_key_delete (key);
        return (0);
    }
    
    ./pthread_key 
    结构体struct_data的地址为 0x0xb7699388
    child1 中 pthread_getspecific(key)返回的指针为:0x0xb7699388
    利用 pthread_getspecific(key)打印 child1 线程中与key关联的结构体中成员值:
    struct_data.i:10
    struct_data.k: 3.141500
    ------------------------------------------------------
    child2 中变量 temp 的地址为 0x0xb6e9838c
    child2 中 pthread_getspecific(key)返回的指针为:0x0xb6e9838c
    
    • 由输出可见,pthread_getspecific() 返回的是与key 相关联数据的指针。
      需要注意的是,在利用这个返回的指针时,它首先是 void 类型的,它虽然指向关联的数据地址处,但并不知道指向的数据类型,所以在具体使用时,要对其进行强制类型转换。
    • 其次,两个线程对自己的私有数据操作是互相不影响的。 也就是说哦,虽然 key 是同名且全局,但访问的内存空间并不是相同的一个。key 就像是一个数据管理员,线程的私有数据只是到他那去注册,让它知道你这个数据的存在。

    参考:
    https://www.xuebuyuan.com/1608934.html
    https://www.jianshu.com/p/d78d93d46fc2

    展开全文
  • pthread_getpecific和pthread_setspecific提供了在同一个线程中不同函数间共享数据即线程存储的一种方法。具体用法为: 1.调用pthread_key_create()来创建一个类型为pthread_key_t类型的变量 该函数有两个参数,第...

    pthread_getpecific和pthread_setspecific提供了在同一个线程中不同函数间共享数据即线程存储的一种方法。具体用法为:
    1.调用pthread_key_create()来创建一个类型为pthread_key_t类型的变量

    该函数有两个参数,第一个参数就是声明的pthread_key_t变量,第二个参数是一个清理函数,用来在线程释放该线程存储的时候被调用。该函数指针可以设成NULL,这样系统将调用默认的清理函数。

    2.调用pthread_setspcific()

    当线程中需要存储特殊值的时候调用该函数,该函数有两个参数,第一个为前面声明的pthread_key_t变量,第二个为void*变量,用来存储任何类型的值。

    3.如果需要取出所存储的值,调用pthread_getspecific()

    该函数的参数为前面提到的pthread_key_t变量,该函数返回void*类型的值。

     

    #include<stdio.h>
    #include<pthread.h>
    #include<string.h>
    pthread_key_t p_key;
     
    void func1()
    {
            int *tmp = (int*)pthread_getspecific(p_key);//同一线程内的各个函数间共享数据。
            printf("%d is runing in %s\n",*tmp,__func__);
     
    }
    void *thread_func(void *args)
    {
     
            pthread_setspecific(p_key,args);
     
            int *tmp = (int*)pthread_getspecific(p_key);//获得线程的私有空间
            printf("%d is runing in %s\n",*tmp,__func__);
     
            *tmp = (*tmp)*100;//修改私有变量的值
     
            func1();
     
            return (void*)0;
    }
    int main()
    {
            pthread_t pa, pb;
            int a=1;
            int b=2;
            pthread_key_create(&p_key,NULL);
            pthread_create(&pa, NULL,thread_func,&a);
            pthread_create(&pb, NULL,thread_func,&b);
            pthread_join(pa, NULL);
            pthread_join(pb, NULL);
            return 0;
    }
    
    

    #gcc thread.c -o test -lpthread
    #./test
    运行结果:

     

    1 is runing in thread_func
    100 is runing in func1
    2 is runing in thread_func
    200 is runing in func1
    

    本文非原创:
    线程数据共享:pthread_getspecific和pthread_setspecific


     

    展开全文
  • 函数pthread_getspecific()正好与pthread_setspecific()相反,其是将 pthread_setspecific()设置的value取出。在使用取出的值前最好是将void*转换成原始数据类型的指针。 四、深入理解线程局部存储机制 ...

     在Linux系统中使用C/C++进行多线程编程时,我们遇到最多的就是对同一变量的多线程读写问题,大多情况下遇到这类问题都是通过锁机制来处理,但这对程序的性能带来了很大的影响,当然对于那些系统原生支持原子操作的数据类型来说,我们可以使用原子操作来处理,这能对程序的性能会得到一定的提高。那么对于那些系统不支持原子操作的自定义数据类型,在不使用锁的情况下如何做到线程安全呢?本文将从线程局部存储方面,简单讲解处理这一类线程安全问题的方法。

    一、数据类型
        在C/C++程序中常存在全局变量、函数内定义的静态变量以及局部变量,对于局部变量来说,其不存在线程安全问题,因此不在本文讨论的范围之内。全局变量和函数内定义的静态变量,是同一进程中各个线程都可以访问的共享变量,因此它们存在多线程读写问题。在一个线程中修改了变量中的内容,其他线程都能感知并且能读取已更改过的内容,这对数据交换来说是非常快捷的,但是由于多线程的存在,对于同一个变量可能存在两个或两个以上的线程同时修改变量所在的内存内容,同时又存在多个线程在变量在修改的时去读取该内存值,如果没有使用相应的同步机制来保护该内存的话,那么所读取到的数据将是不可预知的,甚至可能导致程序崩溃。
        如果需要在一个线程内部的各个函数调用都能访问、但其它线程不能访问的变量,这就需要新的机制来实现,我们称之为Static memory local to a thread (线程局部静态变量),同时也可称之为线程特有数据(TSD: Thread-Specific Data)或者线程局部存储(TLS: Thread-Local Storage)。这一类型的数据,在程序中每个线程都会分别维护一份变量的副本(copy),并且长期存在于该线程中,对此类变量的操作不影响其他线程。如下图:
                                       

    二、一次性初始化
       在讲解线程特有数据之前,先让我们来了解一下一次性初始化。多线程程序有时有这样的需求:不管创建多少个线程,有些数据的初始化只能发生一次。列如:在C++程序中某个类在整个进程的生命周期内只能存在一个实例对象,在多线程的情况下,为了能让该对象能够安全的初始化,一次性初始化机制就显得尤为重要了。——在设计模式中这种实现常常被称之为单例模式(Singleton)。Linux中提供了如下函数来实现一次性初始化:
    #include <pthread.h>

    // Returns 0 on success, or a positive error number on error
    int pthread_once (pthread_once_t *once_controlvoid (*init) (void));
    利用参数once_control的状态,函数pthread_once()可以确保无论有多少个线程调用多少次该函数,也只会执行一次由init所指向的由调用者定义的函数。init所指向的函数没有任何参数,形式如下:
    void init (void)
    {
       // some variables initializtion in here
    }
    另外,参数once_control必须是pthread_once_t类型变量的指针,指向初始化为PTHRAD_ONCE_INIT的静态变量。在C++0x以后提供了类似功能的函数std::call_once (),用法与该函数类似。使用实例请参考https://github.com/ApusApp/Swift/blob/master/swift/base/singleton.hpp实现。

    三、线程局部数据API
        在Linux中提供了如下函数来对线程局部数据进行操作
    #include <pthread.h>

    // Returns 0 on success, or a positive error number on error
    int pthread_key_create (pthread_key_t *keyvoid (*destructor)(void *));

    // Returns 0 on success, or a positive error number on error
    int pthread_key_delete (pthread_key_t key);

    // Returns 0 on success, or a positive error number on error
    int pthread_setspecific (pthread_key_t keyconst void *value);

    // Returns pointer, or NULL if no thread-specific data is associated with key
    void *pthread_getspecific (pthread_key_t key);

    函数pthread_key_create()为线程局部数据创建一个新键,并通过key指向新创建的键缓冲区。因为所有线程都可以使用返回的新键,所以参数key可以是一个全局变量(在C++多线程编程中一般不使用全局变量,而是使用单独的类对线程局部数据进行封装,每个变量使用一个独立的pthread_key_t)。destructor所指向的是一个自定义的函数,其格式如下:
    void Dest (void *value)
    {
        // Release storage pointed to by 'value'
    }
    只要线程终止时与key关联的值不为NULL,则destructor所指的函数将会自动被调用。如果一个线程中有多个线程局部存储变量,那么对各个变量所对应的destructor函数的调用顺序是不确定的,因此,每个变量的destructor函数的设计应该相互独立。

    函数pthread_key_delete()并不检查当前是否有线程正在使用该线程局部数据变量,也不会调用清理函数destructor,而只是将其释放以供下一次调用pthread_key_create()使用。在Linux线程中,它还会将与之相关的线程数据项设置为NULL。
    由于系统对每个进程中pthread_key_t类型的个数是有限制的,所以进程中并不能创建无限个的pthread_key_t变量。Linux中可以通过PTHREAD_KEY_MAX(定义于limits.h文件中)或者系统调用sysconf(_SC_THREAD_KEYS_MAX)来确定当前系统最多支持多少个键。Linux中默认是1024个键,这对于大多数程序来说已经足够了。如果一个线程中有多个线程局部存储变量,通常可以将这些变量封装到一个数据结构中,然后使封装后的数据结构与一个线程局部变量相关联,这样就能减少对键值的使用。

    函数pthread_setspecific()用于将value的副本存储于一数据结构中,并将其与调用线程以及key相关联。参数value通常指向由调用者分配的一块内存,当线程终止时,会将该指针作为参数传递给与key相关联的destructor函数。当线程被创建时,会将所有的线程局部存储变量初始化为NULL,因此第一次使用此类变量前必须先调用pthread_getspecific()函数来确认是否已经于对应的key相关联,如果没有,那么pthread_getspecific()会分配一块内存并通过pthread_setspecific()函数保存指向该内存块的指针。
    参数value的值也可以不是一个指向调用者分配的内存区域,而是任何可以强制转换为void*的变量值,在这种情况下,先前的pthread_key_create()函数应将参数
    destructor设置为NULL
    函数pthread_getspecific()正好与pthread_setspecific()相反,其是将pthread_setspecific()设置的value取出。在使用取出的值前最好是将void*转换成原始数据类型的指针。

    四、深入理解线程局部存储机制
        1. 深入理解线程局部存储的实现有助于对其API的使用。在典型的实现中包含以下数组:
    • 一个全局(进程级别)的数组,用于存放线程局部存储的键值信息
    pthread_key_create()返回的pthread_key_t类型值只是对全局数组的索引,该全局数组标记为pthread_keys,其格式大概如下:
                              
    数组的每个元素都是一个包含两个字段的结构,第一个字段标记该数组元素是否在用,第二个字段用于存放针对此键、线程局部存储变的解构函数的一个副本,即destructor函数。
    • 每个线程还包含一个数组,存有为每个线程分配的线程特有数据块的指针(通过调用pthread_setspecific()函数来存储的指针,即参数中的value)
       2. 在常见的存储pthread_setspecific()函数参数value的实现中,大多数都类似于下图的实现。图中假设pthread_keys[1]分配给func1()函数,pthread API为每个函数维护指向线程局部存储数据块的一个指针数组,其中每个数组元素都与图线程局部数据键的实现(上图)中的全局pthread_keys中元素一一对应。
                         

    五、总结
        使用全局变量或者静态变量是导致多线程编程中非线程安全的常见原因。在多线程程序中,保障非线程安全的常用手段之一是使用互斥锁来做保护,这种方法带来了并发性能下降,同时也只能有一个线程对数据进行读写。如果程序中能避免使用全局变量或静态变量,那么这些程序就是线程安全的,性能也可以得到很大的提升。如果有些数据只能有一个线程可以访问,那么这一类数据就可以使用线程局部存储机制来处理,虽然使用这种机制会给程序执行效率上带来一定的影响,但对于使用锁机制来说,这些性能影响将可以忽略。Linux C++的线程局部存储简单实现可参考https://github.com/ApusApp/Swift/blob/master/swift/base/threadlocal.h,更详细且高效的实现可参考Facebook的folly库中的ThreadLocal实现。更高性能的线程局部存储机制就是使用__thread,这将在下一节中讨论。




    参考:
    [1] Linux/UNIX系统编程手册(上)
    [2] http://www.groad.net/bbs/thread-2182-1-1.html
    [3] http://baike.baidu.com/view/598128.htm

    pthread_getpecific和pthread_setspecific实现同一个线程中不同函数间共享数据的一种很好的方式。


    [cpp]  view plain  copy
    1. /* 
    2.  * ===================================================================================== 
    3.  *       Filename:  thead.c 
    4.  *    Description:  getspecific 
    5.  *        Created:  05/10/2011 12:09:43 AM 
    6.  * ===================================================================================== 
    7.  */  
    8. #include<stdio.h>  
    9. #include<pthread.h>  
    10. #include<string.h>  
    11. pthread_key_t p_key;  
    12.    
    13. void func1()  
    14. {  
    15.         int *tmp = (int*)pthread_getspecific(p_key);//同一线程内的各个函数间共享数据。  
    16.         printf("%d is runing in %s\n",*tmp,__func__);  
    17.    
    18. }  
    19. void *thread_func(void *args)  
    20. {  
    21.    
    22.         pthread_setspecific(p_key,args);  
    23.    
    24.         int *tmp = (int*)pthread_getspecific(p_key);//获得线程的私有空间  
    25.         printf("%d is runing in %s\n",*tmp,__func__);  
    26.    
    27.         *tmp = (*tmp)*100;//修改私有变量的值  
    28.    
    29.         func1();  
    30.    
    31.         return (void*)0;  
    32. }  
    33. int main()  
    34. {  
    35.         pthread_t pa, pb;  
    36.         int a=1;  
    37.         int b=2;  
    38.         pthread_key_create(&p_key,NULL);  
    39.         pthread_create(&pa, NULL,thread_func,&a);  
    40.         pthread_create(&pb, NULL,thread_func,&b);  
    41.         pthread_join(pa, NULL);  
    42.         pthread_join(pb, NULL);  
    43.         return 0;  
    44. }  

    #gcc -lpthread  test.c -o test

    # ./test 

    2 is runing in thread_func

    1 is runing in thread_func

    100 is runing in func1

    200 is runing in func1


    展开全文
  •  void *pthread_getspecific(pthread_key_t key);  int pthread_setspecific(pthread_key_t key, const void *value);   Win32  方法一:每个线程创建时系统给它分配一个LPVOID指针的数组(叫做...
  • arm-linux-gnueabihf-4.7-2012.11-20121123_linux/bin/../lib/gcc/arm-linux-gnueabihf/4.7.3/../../../../arm-linux-gnueabihf/bin/ld: AsyncTCPClient.o: undefined reference to symbol 'pthread_getspecific@@...
  • pthread_getpecific和pthread_setspecific实现同一个线程中不同函数间共享数据的一种很好的方式。[cpp] view plain copy /* * ================================================================================...
  • pthread_once_t once_control = PTHREAD_ONCE_INIT; int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)); 这个api的主要用途是确保所有的线程传入同一个once_control时,init_routine...
  • 函数原型:int pthread_setspecific(pthread_key_t key, const void *value); 功能:使用pthread_setspecific可以为指定线程特定数据键设置线程特定绑定 头文件:#include 由于pthread库非linux默认库,所以需要...
  • eclipse报错:mkl_memory.c:(.text+0xc2e): undefined reference to pthread_getspecific' mkl_memory.c:(.text+0x16d3): undefined reference topthread_key_create’ … 解决方法:1.c++linker中的command中添加-...
  • #include <...void *pthread_getspecific(pthread_key_t key); int pthread_setspecific(pthread_key_t key, const void *value); pthread_key_create(); pthread_key_delete(); pthread_getspecif...
  • void *pthread_getspecific(pthread_key_t key); int pthread_setspecific(pthread_key_t key, const void *value); 说明: TSD 的读写都通过上面两个专门的 Posix Thread 函数进行。 函数 ...
  • /opt/freeradius-server-2.1.12/src/lib/.libs/libfreeradius-radius.so: undefined reference to `pthread_getspecific' /opt/freeradius-server-2.1.12/src/lib/.libs/libfreeradius-radius.so: undefined ...
  • pthread_getpecific和pthread_setspecific实现同一个线程中不同函数间共享数据的一种很好的方式。 #include #include ... int *tmp = (int*)pthread_getspecific(key); printf("%d is fun is %s\
  • "利用 pthread_getspecific(key)打印 child2 线程中与key关联的整型变量temp 值:%d \n " ,   * (( int   * ) pthread_getspecific ( key ))); } int   main  ( void ) {   pthread_t   tid1 ,   ...
  • printf ("利用 pthread_getspecific(key)打印 child1 线程中与key关联的结构体中成员值:\nstruct_data.i:%d\nstruct_data.k: %f\n", ((structtest_struct*)pthread_getspecific (key))->i, ((structtest_struct *)...
  • 2019独角兽企业重金招聘...后来编译选项改为了-pthread就编译过了。 好神奇。 g++ 版本是4.8.4  ubuntu版本是14.04.3 转载于:https://my.oschina.net/u/2461850/blog/1593579
  • pthread_create是UNIX环境创建线程函数 头文件  #include<pthread.h> 函数声明  int pthread_create(pthread_t*restrict tidp,const pthread_attr_t *restrict_attr,void*(*start_rtn)(void*),void *...
  • pthread库windows版下载地址: http://sourceware.org/pthreads-win32/ pthread库中操作线程专有数据帮助文档地址: http://sourceware.org/pthreads-win32/manual/index.html 为线程特定数据创建键 单...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,789
精华内容 2,715
关键字:

pthread_getspecific