使用的基本模板如下(参考APUE):

signal代码序列如下,

pthread_mutex_lock
...
pthread_cond_signal
pthread_mutex_unlock
 
wait代码序列如下,

while (1){
pthread_mutex_lock(&mutex);
while(iCount < 100){
pthread_cond_wait(&cond, &mutex);
}
printf("iCount >= 100\r\n");
iCount = 0;
pthread_mutex_unlock(&mutex);
}

小小几行代码,背后有大学问,这里就把几点重要的地方阐明一下,

首先,signal序列代码中,pthread_cond_signal和pthread_mutex_unlock可以对调,各有利弊参见APUE 11章习题4,以及百度百科词条(pthread_cond_signal),两种写法各有利弊,linux下变成推荐本文开头的写法。

其次,我们始终假定,signal会通知到 不止一个线程。这里会涉及到调度问题,不再详述。

最后,cond_wait是原子的。phtread_cond_wait 的内部实现(注意不是外部通常程序的加解锁)可以理解为如下几个步骤:

1 unlock mutex
2 sleep & wait for cond
3 cond ok & return
4 lock mutex

解锁1和睡眠2是原子的,加锁3和唤醒4是原子的. 原子就是指线程在执行相关步骤时,不会被切换出去。如果不原子会有什么问题呢?

1~2  解锁和睡眠是原子的:lock --> 检查变量不满足 --> unlock --> sleep;如果变量的改变以及通知事件发生在unlock和sleep中间,那么你不会检测到,也就是错过了这次通知.
3~4  加锁和唤醒是原子的:wakeup -- > lock ----> 检查变量是否满足条件:如果在wakeup之后,在lock之前,其他线程可以修改数据,导致我们Lock后检查的数据可能与我们被唤醒的通知不是一个通知,也就是被1号通知唤醒,却检查了2号通知对变量的改变。

也就是说,如果1~2之间wait线程切出去了,那么他将因此损失一次本来可能属于自己的唤醒条件。

你也许会问,SMP条件下,两个线程同时运行,发出signal的线程和wait线程同时进行,1~2之间还是会发生可满足条件导致miss啊?但是,要明白,这个miss事件不是wait线程自己切换造成的,况且,在下次while判断时候,会接到这个提醒——如果,没有同事wait的其他线程的改变。同理,如果3~4之间发生事件(也是第三方线程知识),使本来可满足的条件变为不满足,则下次while循环也能判断出来。

假如有多个线程都在wait,那么wait的线程之间会影响彼此的判断,但是,这就是你允许多个wait的必须前提啊?!这还有神马可解释的呢!

关于while循环的作用 参见 http://blog.csdn.net/joogle/article/details/8010245

pthread_cond_wait的原子性的更多相关文章

  1. pthread_cond_wait 详解

    转自:http://www.xuebuyuan.com/2173853.html pthread_cond_wait() 用于阻塞当前线程,等待别的线程使用pthread_cond_signal()或 ...

  2. pthread_cond_wait

    while(1) 33 { 34 mm* p = NULL; 35 pthread_mutex_lock(&mutex); 36 while(head == NULL) 37 pthread_ ...

  3. Java并发_volatile实现可见性但不保证原子性

    读后感 介绍了volatile实现可见性的基本原理 介绍了volatile不能实现原子性的示例,volatile复合操作不能实现原子性,读取值后在自增前改值可能被其它线程读取并修改,自增后刷新值可能会 ...

  4. volatile不能保证原子性

    1.看图自己体会 2.体会不了就给你个小程序 package cs.util; public class VolatileDemo { private volatile int count =0; p ...

  5. 为什么volatile不能保证原子性而Atomic可以?

    在上篇<非阻塞同步算法与CAS(Compare and Swap)无锁算法>中讲到在Java中long赋值不是原子操作,因为先写32位,再写后32位,分两步操作,而AtomicLong赋值 ...

  6. 【系统架构】缓存Memcache 使用原子性操作add,实现并发锁

    原文地址 memcache中Memcache::add()方法在缓存服务器之前不存在key时, 以key作为key存储一个变量var到缓存服务器.我们使用add来向服务器添加一个键值对应,如果成功则添 ...

  7. redis原子性读写操作之LUA脚本和watch机制

    最近在开发电商平台的子系统--储值卡系统,系统核心业务涉及到金额消费以及库存控制,因此为了解决建立在内存上高并发情况下的事务控制,使用了spring封装的RedisTemplate执行lua脚本进行原 ...

  8. java并发编程学习笔记(一)初识并发原子性

    1.并发的意义 现在是一个多核的时代,并发的存在意义就是为了能够充分利用多核计算机的优势,提高程序的运行效率: 2.并发的风险 竞争-----多个线程对内存数据数据进行读写操作时,对数据处理结果的一个 ...

  9. Objective-C 中,atomic原子性一定是安全的吗?

    我们在学习OC的时候认为,atomic使用了原子性,保证了线程安全,事实真的是这样吗? nonatomic的内存管理语义是非原子性的,非原子性的操作本来就是线程不安全的,而atomic的操作是原子性的 ...

随机推荐

  1. ESI 动态缓存技术

    任何一个Web网站的内容都是在不断更新和变化,但这并不意味这这个网站的内容就是动态内容,事实上,动态的内容是指用户每次点击 相同的链接时取的的内容是由Web服务器应用程序生成的,如常见得ASP,JSP ...

  2. Ubuntu 16.10 虚拟机安装记录

    一定要选自定义. 这里一定要选 稍后安装操作系统  都是坑! 启动时出现'SMBus Host Controller not enabled'错误提示,进不到图形界面. 解决办法:1.在启动Ubunt ...

  3. [设计模式] javascript 之 迭代子模式

    迭代子模式:定义 迭代子模式,又称游标模式,是一种用于对聚集进行顺序访问规则的模式,是一种行为模式:它用于提供对聚集对象的一种统一的访问接口,使客户能够在不了解聚集对象内部结构的情况对聚集对象进行访问 ...

  4. hessian接口参数,子类与父类不能有同名字段解决方法

    hessian默认是使用 com.caucho.hessian.io.JavaSerializer 序列化,同名字段子类字段值被赋值两次,最终用父类null值赋给了子类同名字段,解决方法就是 指定序列 ...

  5. xcode7 The operation couldn't be completed.

    问题描述:当运行Xcode6时,编译代码成功,但是登陆模拟器失败,显示错误:The Operation couldn't be completed.(LaunchServicesError error ...

  6. php中向mysql插入数据

     $sql='insert into news(title,subtitle,source,publishtime,content,image,author) values("'.unico ...

  7. lintcode 75 Find Peak Element

    Hi 大家,这道题是lintcode上的find peak element的题,不是leecode的那道, 这两道题是有区别的,这道题的题目中说明了:只有左右两侧的数都小于某个元素,这种才是峰值, 而 ...

  8. 移动端rem切图

    1.为什么用rem 根据屏幕大小,自动调整大小 2.如何使用rem 分以下几步 a.用ps把设置稿弄成640px或者750px的(记得等比例缩放) b.调试时记得把浏览器默认最小字体设置为最小.手机端 ...

  9. word20161130

    1. even 偶数 [ǒu shù][词典] even; [数] even number;[例句]在本例中,slot A中有奇数个阵列,slot B中有偶数个阵列.In this example, ...

  10. 关于ubuntukylin安装后界面中英文混杂的问题

    起因 一直使用的是ubuntu原版的系统,ubuntukylin出来后也没用使用过.一次去其论坛逛了一圈之后决定使用一下. 安装后的截面和ubuntu原版的差不多,还是挺漂亮的. 但是有一个问题是,安 ...