使用的基本模板如下(参考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. 2014 牡丹江区域赛 B D I

    http://acm.zju.edu.cn/onlinejudge/showContestProblems.do?contestId=358 The 2014 ACM-ICPC Asia Mudanj ...

  2. List之Union(),Intersect(),Except()

    http://www.cnblogs.com/qinpengming/archive/2012/12/03/2800202.html List之Union(),Intersect(),Except() ...

  3. 包介绍 - UriTemplates (用于处理格式化Uri模板)

    UriTemplates 用于处理格式化Uri模板 PM> Install-Package Tavis.UriTemplates 设置Uri Path Segment [Fact] public ...

  4. STM32F10xx CAN BUS相关库文件"stm32f10x_can.c"内的库函数解析

    一.背景: 还是继续CAN通信,要节省开发时间,使用库函数可大大降低开发周期,并且还能确保寄存器的配置几 乎是万无一失,所以,在此就STM32F10xx的CAN操作库函数的使用做个简析. STM32有 ...

  5. 【android-tips】如何在view中取得activity对象

    (转载请注明出处:http://blog.csdn.net/buptgshengod) 今天想实现在view中返回上一个activity的功能,想了半天.因为在虽然view是包含于一个activity ...

  6. Gunicorn 问题

    Does Gunicorn suffer from the thundering herd problem? The thundering herd problem occurs when many ...

  7. iOS开发——网络篇——HTTP/NSURLConnection(请求、响应)、http响应状态码大全

    一.网络基础 1.基本概念> 为什么要学习网络编程在移动互联网时代,移动应用的特征有几乎所有应用都需要用到网络,比如QQ.微博.网易新闻.优酷.百度地图只有通过网络跟外界进行数据交互.数据更新, ...

  8. Docker 容器测试全探索

    导读 当我们构建好Docker镜像并利用多套容器共同组合成应用程序,建立起持续交付通道,了解了如何将新创建的镜像纳入到生产或者测试环境当中之后,新的问题来了——我们该如何测试自己的Docker容器?测 ...

  9. 仿jQuery的siblings效果的js原生代码

    仿jQuery的siblings效果的js原生代码 <previousSibling> 属性返回选定节点的上一个同级节点(在相同树层级中的前一个节点). <nextSibling&g ...

  10. tableView 选中cell时,获取到当前cell

    // >> 找到当前选中的cell,设置选中时的cell背景色 SideTableViewCell * cell = (SideTableViewCell *)[tableView cel ...