NPTL提供了互斥体 pthread_mutex_t 类型进行线程同步,防止由于多线程并发对全局变量造成的不正确操作。使用 pthread_mutext_t 对数据进行保护已经可以实现基本的数据同步,NPTL又提供了pthread_cond_t 条件变量与pthread_mutext_t一起使用实现高效的线程同步保护数据。有了互斥变量pthread_mutext_t为什么还要引入条件变量pthread_cond_t呢? 原因就是防止CPU空转,一个线程获得互斥量之后,另外一个线程如果想获取该互斥量,就会不断的去查询这个互斥量是否已经空闲可以被自己占用,于是浪费了CPU周期。引入条件变量pthread_cond_t之后,如果条件不满足,线程进入睡眠状态,不会浪费CPU周期。

  NPTL进行线程同步的一般结构如下:

thread 1:
pthread_mutex_lock(&mutex);
while (!condition)
pthread_cond_wait(&cond, &mutex);
/* 实际操作,修改condition为无效 */
pthread_mutex_unlock(&mutex); thread2:
pthread_mutex_lock(&mutex);
/* 实际操作,修改condition为有效 */
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);

  标准代码结构是像上面这样,针对上面的结构提几个问题?

  1. 为什么要将pthread_cond_wait 放在while(!condition)循环内呢,为什么要有while(!condition)的存在呢?

    2. pthread_cond_t 为什么要和 pthread_mutex_t 一起使用呢,使用pthread_cond_signal的线程不使用pthread_mutext 行不行? 

  在回答上面的问题之前先介绍一下最核心的pthread_cond_wait(&cond, &mutex)在不同情况下都会干些什么。

  1. 程序运行到pthread_cond_wait() 条件发生,代码继续向下执行。

  2. 程序运行到pthread_cond_wait() 条件未发生,函数调用首先会释放mutex(打开锁),并使当前线程进入睡眠状态。

  3. 睡眠在pthread_cond_wait()上的线程被signal唤醒,pthread_cond_wait()首先去获得锁(尝试重新获得该mutex直到获得)。

  pthread_cond_wait()的行为为下面的讨论做一个铺垫。现在来考虑回答上面的问题,我们可以从多线程乱序执行做为切入点,thread1 有可能比thread2 先执行,thread2 也有可能比thread1先执行。

  1.首先考虑,如果thread2先执行并且已经执行到 pthread_cond_signal() 但是thread1甚至都还没有运行,更别说进入到pthread_cond_wait()状态,这时候没有 while(!condition) 会怎么样?

  显然thread2已经发送了singal了,但是没有接收者,此时出现了丢信号的情况,即如果没有 while(!condition) 当thread1进入到pthread_cond_wait()的时候就会睡眠,唤醒信号丢失的情况发生,在这种情况下如果有 while(!condition) 的存在则不会执行pthread_cond_wait() 直接执行下面的代码。

  那么用 if(!condtion) 不是也可以解决上面的问题吗? 不错是可以解决上面的问题,但是会带来新的问题。考虑这种情况:如果signal同时唤醒了多个wait在该条件上的线程(pthread_cond_broadcast 或者出现传说中的Spurious wakeup),那使用if(!condtion) 就是不行的。 这是因为,各个多个被唤醒的线程肯定会有一个会先进入被这个mutex保护的临界区(回忆上面介绍的pthread_cond_wait()函数在线程醒来之前会尝试去持有锁直到持有为止),Linux上规定是低优先级的线程先获得该mutex,然后进行了操作,并修改了condition变量,释放了mutex,此时另一个正在睡眠中但同时也在尝试获取该mutex的线程被唤醒,然后直接就向下执行,此时就会导致多线程同步失败。如果使用while(!condtion)再次进行检查则不会出现同步失败的问题。

  2.第二个问题相对简单,如果cond不和mutex一起使用,那么任何可以访问cond的线程都可能唤醒睡眠在某个mutex上的线程,所以需要mutex对cond的保护,以确保有资格的线程才能对某个线程进行唤醒操作。

  理解条件变量的关键还是需要理解pthread_cond_wait()都干了些什么!

  

NPTL 多线程同步  条件变量 互斥变量 Linux

NPTL 线程同步方式的更多相关文章

  1. 线程同步方式之互斥量Mutex

    互斥量和临界区非常相似,只有拥有了互斥对象的线程才可以访问共享资源,而互斥对象只有一个,因此可以保证同一时刻有且仅有一个线程可以访问共享资源,达到线程同步的目的. 互斥量相对于临界区更为高级,可以对互 ...

  2. C++线程同步的四种方式(Windows)

    为什么要进行线程同步? 在程序中使用多线程时,一般很少有多个线程能在其生命期内进行完全独立的操作.更多的情况是一些线程进行某些处理操作,而其他的线程必须对其处理结果进行了解.正常情况下对这种处理结果的 ...

  3. C++ 线程同步的四种方式

    程之间通信的两个基本问题是互斥和同步. (1)线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒. (2)线程互 ...

  4. C#线程同步的几种方法

    一.volatile关键字 volatile是最简单的一种同步方法,当然简单是要付出代价的.它只能在变量一级做同步,volatile的含义就是告诉处理器, 不要将我放入工作内存, 请直接在主存操作我. ...

  5. Delphi 线程同步技术(转)

    上次跟大家分享了线程的标准代码,其实在线程的使用中最重要的是线程的同步问题,如果你在使用线程后,发现你的界面经常被卡死,或者无法显示出来,显示混乱,你的使用的变量值老是不按预想的变化,结果往往出乎意料 ...

  6. C#线程同步总结

    对于整数数据类型的简单操作,可以用Interlocked类的成员来实现线程同步.对于复杂的线程同步,有以下几个方法: 1.lock关键字: 2.Monitor: 3.同步事件和等待句柄: 4.Mute ...

  7. MFC 多线程及线程同步

    一.MFC对多线程编程的支持 MFC中有两类线程,分别称之为工作者线程和用户界面线程.二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环. 工作者线程没有消息机制,通常 ...

  8. C#并行编程(6):线程同步面面观

    理解线程同步 线程的数据访问 在并行(多线程)环境中,不可避免地会存在多个线程同时访问某个数据的情况.多个线程对共享数据的访问有下面3种情形: 多个线程同时读取数据: 单个线程更新数据,此时其他线程读 ...

  9. 线程同步 –Mutex和Semaphore

    上一篇介绍了同步事件EventWaitHandle,以及它的两个子类型AutoResetEvent和ManualResetEvent.下面接着介绍WaitHandle的另外两个子类型Mutex和Sem ...

随机推荐

  1. mysqld.exe 占了400M内存的问题

    最近遇到了服务器总是停机的问题,虽然它自己只有2G的内存,不过实际部署的应用访问量非常小,也不至于2G就不够用,所以开始了给服务器瘦身的计划. 看着任务管理器里面的各个进程,发现吃内存最厉害的是mys ...

  2. 动态变化的OO设计

    今天看到个题目:对象会动态的变化. 游戏精灵,有人和神仙,但是随着人的不断积分,会升级为神仙:神仙也可能会因为积分的减少而降级为人.这种情况怎么画出个类图来. 这是第一版的设计,正常思维.人和神仙都是 ...

  3. Django抛错不存在(DoesNotExist)

    from django.core.exceptions import ObjectDoesNotExist try: disabledusers.objects.get(sAMAccountName= ...

  4. Scala 具体的并行集合库【翻译】

    原文地址 本文内容 并行数组(Parallel Array) 并行向量(Parallel Vector) 并行范围(Parallel Range) 并行哈希表(Parallel Hash Tables ...

  5. Linux2.6 内核的 Initrd 机制解析(转)

    from: https://www.ibm.com/developerworks/cn/linux/l-k26initrd/ 简介: Linux 的 initrd 技术是一个非常普遍使用的机制,lin ...

  6. 小试ijkplayer编译

    同步发表于 http://avenwu.net/ijkplayer/2015/05/07/hands_on_ijkplayer_preparation 谈到视频播放大家都知道ffmpeg,基于其的衍生 ...

  7. D3 & Data Visualization in Ext JS

    通过适配器可以在ExtJs中轻松的集成D3的展示能力 http://video.sencha.com/watch/zvUjnFJ91xVvuwdTh2zjqP?mkt_tok=eyJpIjoiWm1a ...

  8. android中自定义view---实现竖直方向的文字功能,文字方向朝上,同时提供接口,判断当前touch的是哪个字符,并改变颜色

    android自定义view,实现竖直方向的文字功能,文字方向朝上,同时提供接口,判断当前touch的是哪个字符,并改变颜色. 由于时间比较仓促,因此没有对代码进行过多的优化,功能远远不如androi ...

  9. iOS WKWebView详解

    UIWebView就不用说了,这个过时了,现在iOS8以后建议都使用WKWebView. WKWebView 是现代 WebKit API 在 iOS 8 和 OS X Yosemite 应用中的核心 ...

  10. C#导出Excel,并且设置Excel单元格格式,合并单元格.

    注:要添加COM组件 Microsoft Excel 11.0 Object Library  引用. 具体代码如下: using System; using System.Collections.G ...