线程安全

线程安全与每数据存储

1.线程安全

若函数可以同时供多个线程同时安全调用,暗恶魔称之为线程安全函数,如果函数不是线程安全,则不能够并发调用

  • 实现线程安全的方式

    1. 将函数与互斥量关联使用,在调用函数时将其锁定,在函数返回时解锁

      该方法的优点在于简单,但是这也就意味着同时只能有一个线程执行该函数,如果各线程在执行此函数时耗费了相当多的时间,那么该执行方式就相当于串行了,导致并发能力的丧失

    2. 将共享变量与互斥量关联起来

      即在函数即将进入临界区时去获得和释放互斥量,这允许多个线程去并发执行一个函数

  • 非线程安全的函数

    以下所列函数均为非线程安全(至少不应该把他们当做是)


    非线程安全函数.png
  • 可重入函数与不可重入函数

    可重入函数无需使用互斥量即可保证线程安全,关键在于避免对全局变量和静态变量的使用,需要返回给调用者的信息,应该都存储于由调用者分配的缓冲区

    对于一些接口不可重入的函数,SUSv3为其定义了以后缀_r结尾的可重入"替身",这些替身函数要求由调用者来分配缓冲区,并且将缓冲区地址用于给函数用于返回结果


    不可重入函数替身
2.一次性初始化
  • pthread_once

    当pthread_once()首次被任何线程所调用时,会执行初始化动作

    #include<pthread.h>
    int pthread_once(pthread_once_t *once_control, void (*init)(void));
                                                          //成功:返回0, 失败:返回一个正数
    

    init是一个调用者自定义的函数,格式如下

    void init(void){
    //...
    }
    

    当使用pthread_once()函数时,会使用init()函数来进行初始化

    once_control是一个指针,指向初始化为PTHREAD_ONCE_INIT的静态变量,即

    static pthread_once_t once_var = PTHREAD_ONCE_INIT;
    

    对该函数的首次调用将改变once_control的值,使得后续调用不会再次执行init

3.线程特有数据

在一个进程中定义的全局或静态变量都是所有线程可见的,即每个线程共同操作一块存储区域。而有时我们可能有这样的需求:对于一个全局变量,每个线程对其的修改只在本线程内有效,各线程之间互不干扰。即每个线程虽然共享这个全局变量的名字,但这个变量的值就像只有在本线程内才会被修改和读取一样
线程特有数据(TSD)使得函数的移位每个调用线程分别维护一份变量的副本,线程特有的数据是长期存在的,在同一个线程对相同函数的历次调用期间,每个线程的变量会持续存在,函数可以量每个调用线程返回各自的结果缓冲区

  • pthread_key_create

    pthread_key_create会创建一个类型为pthread_key_t 类型的私有数据变量(key)

    #include<pthread.h>
    int pthread_key_create(pthread_key_t *key, void (destructor)(void*))
                                                      //成功:返回0 失败:返回一个正数
    

    参数介绍:

    1. key

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

    2. destructor

      析构器函数,当线程退出时,如果线程私有数据地址不是非NULL,此函数会被自动调用,如果将该函数指针设置为NULL,那么系统将调用默认的清理函数

      destructor的函数定义如下

      void destructor(void *arg){
      //...
      }
      
  • pthread_key_delete

    注销线程的私有数据。这个函数并不会检查当前是否有线程正在使用线程私有数据(key),也不会调用清理函数destructor(),而只是将线程私有数据(key)释放一共下一次使用

    #include<pthread.h>
    int pthread_key_delete(pthread_key_t key);
                                              //成功:0 失败:正数
    

    参数:

    1. key

      待注销的私有数据

  • pthread_setspecific

    该函数会设置线程的私有数据(key)与value关联(而非与其所指的内容关联)

    #include<pthread.h>
    int pthread_setspecific(pthread_key_t key, const void *value);
                                              //成功: 0 失败:正数
    

    参数:

    1. key

      线程的私有数据

    2. value

      与key相关联的指针

  • pthread_getspecific

    读取线程私有数据(key)所关联的值

    void* pthread_getspecific(pthread_key_t key);
                                          //成功:与key关联的value   失败:NULL
    

线程特有数据的实现

典型的实现方法会包含以下两个数组

  • 一个全局数组pthread_keys(即整个进程只包含一个)

    该数组存放线程特有数据(key)的信息,数组中的每个元素都包含两个字段,一个标记该数组元素是否在用,另一个则标记与key相关联的解构函数的地址


    全局数组
  • 每个线程自身的一个数组

    因为一个线程可以调用很多函数,所以一个线程就会拥有很多它在不同函数中所分配的数据块,该数组存放着该线程所持有的所有数据块的指针

这两个数组之间的关系如下图所示


关系

在不同函数中调用pthread_key_create(),相当于只是在pthread_key数组增加了一个条目而已,其返回的key只是全局pthread_key数组中的一个索引

调用pthread_setspecific()时key与value是一一对应的关系,相应的操作就是在线程自身的数组中增加一个条目tsd[key],其内容为我们传递的value

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352

推荐阅读更多精彩内容