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. quick -- 创建精灵和动作

    local imgBg = display.newSprite("666666.jpg") :pos(display.cx, display.cy) :addTo(self) , ...

  2. 关于 c# 操作 world

    把数据存放在datatable 中并循环取出来数据然后再保存在world中 protected void ExportToWord(DataSet Ads) { try { Object Nothin ...

  3. goldengate一些参数整理

    转自:http://blog.csdn.net/lemontree1123/article/details/46603549 manager参数: AUTOSTART:指定在mgr启动时自动启动那些进 ...

  4. XML 文档和数据

    .NET Framework 4.5 其他版本 .NET Framework 提供了一组全面而集成的类,可用来方便地生成可以识别 XML 的应用程序. 通过以下命名空间中的类,可以分析和编写 XML, ...

  5. IOC错误

    问题描述: The type DbConnection cannot be constructed. You must configure the container to supply this v ...

  6. 采用ODAC,ODBC连接Oracle【转】

    采用ODAC,ODBC连接Oracle 在没有装oracle的环境中,偶尔会需要访问数据库(Word文档查看数据,开发项目运行等等),简单介绍我用过的方案. 一:ODAC 1.介绍.ODAC,全称:o ...

  7. struts2:异常处理

    Struts2框架提供了自己的异常处理机制,只需要在struts.xml文件中配置异常处理即可,而不需要在Action方法中来捕捉异常. 传统方法 public String execute() th ...

  8. javaBean List Map json(转)

    1.依赖的包 根据:http://json-lib.sourceforge.net/ 可见json-lib使用需要依赖一下包:   下载地址:http://download.csdn.net/down ...

  9. Linux流量监控工具-iftop教程

    Linux流量监控工具-iftop教程http://automationqa.com/forum.php?mod=viewthread&tid=2854&fromuid=2

  10. Golang pprof heap profile is empty

    Q: When you use `go tool pprof` get heap data, profile is empty. A: The default sampling rate is 1 s ...