NPTL 线程同步方式
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 线程同步方式的更多相关文章
- 线程同步方式之互斥量Mutex
互斥量和临界区非常相似,只有拥有了互斥对象的线程才可以访问共享资源,而互斥对象只有一个,因此可以保证同一时刻有且仅有一个线程可以访问共享资源,达到线程同步的目的. 互斥量相对于临界区更为高级,可以对互 ...
- C++线程同步的四种方式(Windows)
为什么要进行线程同步? 在程序中使用多线程时,一般很少有多个线程能在其生命期内进行完全独立的操作.更多的情况是一些线程进行某些处理操作,而其他的线程必须对其处理结果进行了解.正常情况下对这种处理结果的 ...
- C++ 线程同步的四种方式
程之间通信的两个基本问题是互斥和同步. (1)线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒. (2)线程互 ...
- C#线程同步的几种方法
一.volatile关键字 volatile是最简单的一种同步方法,当然简单是要付出代价的.它只能在变量一级做同步,volatile的含义就是告诉处理器, 不要将我放入工作内存, 请直接在主存操作我. ...
- Delphi 线程同步技术(转)
上次跟大家分享了线程的标准代码,其实在线程的使用中最重要的是线程的同步问题,如果你在使用线程后,发现你的界面经常被卡死,或者无法显示出来,显示混乱,你的使用的变量值老是不按预想的变化,结果往往出乎意料 ...
- C#线程同步总结
对于整数数据类型的简单操作,可以用Interlocked类的成员来实现线程同步.对于复杂的线程同步,有以下几个方法: 1.lock关键字: 2.Monitor: 3.同步事件和等待句柄: 4.Mute ...
- MFC 多线程及线程同步
一.MFC对多线程编程的支持 MFC中有两类线程,分别称之为工作者线程和用户界面线程.二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环. 工作者线程没有消息机制,通常 ...
- C#并行编程(6):线程同步面面观
理解线程同步 线程的数据访问 在并行(多线程)环境中,不可避免地会存在多个线程同时访问某个数据的情况.多个线程对共享数据的访问有下面3种情形: 多个线程同时读取数据: 单个线程更新数据,此时其他线程读 ...
- 线程同步 –Mutex和Semaphore
上一篇介绍了同步事件EventWaitHandle,以及它的两个子类型AutoResetEvent和ManualResetEvent.下面接着介绍WaitHandle的另外两个子类型Mutex和Sem ...
随机推荐
- Android源码分析-全面理解Context
前言 Context在android中的作用不言而喻,当我们访问当前应用的资源,启动一个新的activity的时候都需要提供Context,而这个Context到底是什么呢,这个问题好像很好回答又好像 ...
- HttpURLConnection GET/POST写法
现在虽然HttpClient很好使,但也有人在用最原生的HttpURLConnection, 记录一下,备忘之. public class HttpUrlConnect { //get请求 publi ...
- Scala 深入浅出实战经典 第54讲:Scala中复合类型实战详解
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- C# HttpWebRequest 绝技 根据URL地址获取网页信息
如果要使用中间的方法的话,可以访问我的帮助类完全免费开源:C# HttpHelper,帮助类,真正的Httprequest请求时无视编码,无视证书,无视Cookie,网页抓取 1.第一招,根据URL地 ...
- spring中配置了事务,数据业务层捕获异常,事务配置不成功?
原理:spring aop 异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样aop代理才能捕获到方法的异常,才能进行回滚,默认情况下aop只捕获runtimeexception的异常 ...
- Oracle外键不加索引会引起死锁问题
转载链接:http://www.jb51.net/article/50161.htm 这篇文章主要介绍了Oracle外键不加索引引起死锁的情况及解决,需要的朋友可以参考下 --创建一个表,此表作为子表 ...
- OBS---环境配置之#include <D3DX10.h>报错
一.先贴错误 因为这个笔记主要记录我如何整好这个OBS源码环境的,给需要的童鞋一个参考 1.1.#include <D3DX10.h> 报错 没有这个 解决方案:把2,3先解决了就水到渠 ...
- mmo设计
基于多人格斗系统设计. 总体 1.放技能/使用道具,行走,公告,聊天 共性: A.服务端代理推送 B.管道内推送 2.玩家信息(统一玩家信息查看,去除每个模块自己实现) 3.怪物掉落(统一掉落控制.领 ...
- Dbvisualizer9.0.6 解决中文乱码
一.设置编辑器的编码 Tools->Tools Properties ->General->File Encoding 设置为UTF-8 二.如果数据库为UTF-8,则要在连接时做以 ...
- scanf中的[]
今天被问到一个问题,如何用scanf将 hello-my-world中的三个单词, hello my world 分别放到三个char数组中去 于是用到了scanf中的[] [ ] 扫描字符集合,比如 ...