产生这个问题的起因是这样的:

‎[:] ‎<‎tong‎>‎ lilydjwg: 主线程要启动N个子线程, 一个局部变量作为把同样的参数传入每一个子线程. 子线程在开始的十行会处理完参数. 我发现这中间会有同步问题. 需要锁一下, 或者主线程要线性的逐个完成初始化.
‎[:] ‎<‎tong‎>‎ 主线程就是一个i<N的循环. 局部变量会根据i
‎[:] ‎<‎tong‎>‎ 修改
‎‎[16:53] <‎tong‎>‎ 就是, 线程A阻塞, 等待线程B处理完资源X后, 线程A将X的内容修改.

很显然, 这个问题, 只需要用一个信号量便可解决.

但是有没有更好的方式呢?, 于是我想到了条件变量, 细研究了条件变量的用法之后发现, 条件变量需要一个条件变量同时还需要一个互斥锁来混合使用. 虽然可以实现我的需求, 但是很显然这很麻烦.

所以, 问题在于, 这么麻烦的一组API, 它的应用场景是什么?

经过查看资料, 分析, 讨论.之后. 大概的结论如下:

‎[:] ‎<‎tong‎>‎ 当条件复杂的时候, 就需要条件变量了. 写起来也会比较方便. 我的场景简单,就用信号量就行了. 大概是这么理解的

一个比较详细的解释:

https://www.zhihu.com/question/30641734

作者:钓雪
链接:https://www.zhihu.com/question/30641734/answer/105402533
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 需要condition变量的原因本质上就是程序执行顺序的不确定性.管程(monitor)只是保证了同一时刻只有一个进程在管程内活动,即管程内定义的操作在同一时刻只被一个进程调用(由编译器实现).但是这样并不能保证进程以设计的顺序执行,因此需要设置condition变量,让进入管程而无法继续执行的进程阻塞自己.也可以这么说,由于程执行顺序的不确定性,进程在entry序列中的顺序并不一定是我们想要的,而condition变量就是用来操作entry序列的.有了condition变量,我们就可以让在自己前驱进程之前提前进入管程的进程挂起自己,退回到entry序列中重新排队.具体来说: 以生产者-消费者问题(也称有限缓冲问题)为例, 如果我们不使用信号量(semaphore)而简单的用整形变量count来记录buffer中的数据项数目, 用系统调用sleep()阻塞进程 和 wakeup() 唤醒进程 程序如下#define TRUE 1
#define MAX 100 void insert_item(int);
int remove_item(); int count = ; void producer()
{
int item; while(TRUE)
{
item = produce_item();
if( count == MAX ) sleep();
insert_item(item);
count += ;
if( count == ) wakeup(consumer); /*buffer由空变非空后唤醒挂起的消费者*/
}
} void consumer()
{
int item; while(TRUE)
{
if( count == ) sleep();
item = remove_item();
count -= ;
/*buffer由满变不满后唤醒生产者*/
if( count == MAX - ) wakeup(producer);
consume_item(item);
}
}
这样写的问题在于 我们不能保证 count 变量的互斥访问.如果producer在consumersleep之前发送wakeup信号便会导致错误,程序执行顺序如下1. 消费者 在检查到count == 0而未休眠2. 生产者 执行 count += 并且向 消费者发送 wakeup信号,. 由于此时消费者并未sleep,wakeup信号丢失4. 之后消费者执行sleep休眠5. 生产者不断生产而消费者休眠直到buffer填满6. 生产者消费者都休眠,无法相互唤醒如果我们将访问count变量的过程写入管程中,就可以使两个进程对count进行互斥访问,从而解决这个问题.但是,管程并不知道编程者的逻辑,它并不能在生产者在count == MAX时挂起自己,也不能在 count == MAX - 时唤醒生产者,这时就需要使用条件变量.我们定义管程#define MAX 100 /* 定义管程 PC */
monitor PC
{
int count = ;
/* 我们使用条件变量full 表示被填满的buffer, empty 表示空的buffer */
conditon full, empty; void insert(int item)
{
/* 当buffer满的时候,我们在full上将插入操作阻塞 */
if ( count == MAX ) wait(&full);
insert_item(item);
count += ;
/* 当buffer不空的时候,我们在empty上唤醒取出操作 */
if ( count == MAX - ) signal(&empty);
} int remove()
{
/* 当buffer空的时候,我们在empty上将取出操作阻塞 */
if( count == ) wait(&empty);
remove_item(item);
count -= ;
/* 当buffer不满的时候,我们在full上唤醒插入操作 */
return item;
if( count == MAX - ) signal(&full);
}
} void producer()
{
int item;
item = produce_item();
/*调用管程中的函数 */
PC.insert(item);
} void consumer()
{
int item;
/*调用管程中的函数 */
item = PC.remove();
consumer_item();
}
*** 注意 以上代码 用类似于C的代码写成 ,但 C语言并不支持管程 ****** JAVA 支持管程 在method前加sychronized 关键字 可以保证在一个线程调用 ****** synchronized method时 不允许其他线程调用该对象中其他synchronized method ***这样以来, 由于管程保证内部内部操作的互斥性,操作就不会wait()的前一刻被signal(),从而不会发生生产者和消费者都被阻塞而无法相互唤醒的情况了.同时我们的生产者和消费者也可以在恰当的时候阻塞自己.条件变量不止存在于管程中,在多线程库中也是普遍存在的.Unix的多线程库Pthread中也使用条件变量协调进程的同步.

另外, 原来, 这个东西叫管程 https://zh.wikipedia.org/wiki/%E7%9B%A3%E8%A6%96%E5%99%A8_(%E7%A8%8B%E5%BA%8F%E5%90%8C%E6%AD%A5%E5%8C%96)#.E6.A2.9D.E4.BB.B6.E8.AE.8A.E6.95.B8.28Condition_Variable.29

值得一提的是: 东尼·霍尔证明了管程在逻辑上与信号量是等价的。

此外,还发现了一个以前没有接触过的概念和API pthread_barrier_wait

http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_barrier_wait.html

最后,顺便一贴,没啥关系的

https://jin-yang.github.io/post/program-c-linux-pthreads-synchronize.html

------------- 新的想法 @ 2017-11-09 ----------------

基于昨天讨论的条件变量和信号量等价问题. 我发现原来互斥锁也是信号量实现的. 那是不是说,在线程或进程同步的时候,光有信号量就够了?

[development][C] 条件变量(condition variables)的应用场景是什么的更多相关文章

  1. 深入解析条件变量(condition variables)

    深入解析条件变量 什么是条件变量(condition variables) 引用APUE中的一句话: Condition variables are another synchronization m ...

  2. python线程条件变量Condition(31)

    对于线程与线程之间的交互我们在前面的文章已经介绍了 python 互斥锁Lock / python事件Event , 今天继续介绍一种线程交互方式 – 线程条件变量Condition. 一.线程条件变 ...

  3. Linux组件封装(二)中条件变量Condition的封装

    条件变量主要用于实现线程之间的协作关系. pthread_cond_t常用的操作有: int pthread_cond_init(pthread_cond_t *cond, pthread_conda ...

  4. python线程的条件变量Condition的用法实例

      Condition 对象就是条件变量,它总是与某种锁相关联,可以是外部传入的锁或是系统默认创建的锁.当几个条件变量共享一个锁时,你就应该自己传入一个锁.这个锁不需要你操心,Condition 类会 ...

  5. [转] 条件变量(Condition Variable)详解

    http://www.wuzesheng.com/?p=1668 条件变量(Condtion Variable)是在多线程程序中用来实现“等待->唤醒”逻辑常用的方法.举个简单的例子,应用程序A ...

  6. 条件变量(Condition Variable)详解

    条件变量(Condtion Variable)是在多线程程序中用来实现“等待->唤醒”逻辑常用的方法.举个简单的例子,应用程序A中包含两个线程t1和t2.t1需要在bool变量test_cond ...

  7. java 并发时使用条件变量--Condition

    lock--unlock的方式在实际中使用较少,一般使用synchronized获取对象的内部锁替代,但是lock--unlock对了解synchronized有很大的帮助. 创建一个bank对象用于 ...

  8. linux 条件变量与线程池

    条件变量Condition Variables 概述 1. 条件变量提供了另外一种线程同步的方式.如果没有条件变量,程序需要使用线程连续轮询(可能在临界区critical section内)方式检查条 ...

  9. 互斥量、条件变量与pthread_cond_wait()函数的使用,详解(二)

    1.Linux“线程” 进程与线程之间是有区别的,不过linux内核只提供了轻量进程的支持,未实现线程模型.Linux是一种“多进程单线程”的操作系统.Linux本身只有进程的概念,而其所谓的“线程” ...

随机推荐

  1. Atitit 提升效率 界面gui方面的前后端分离与cbb体系建设 规范与推荐标准

    Atitit 提升效率 界面gui方面的前后端分离与cbb体系建设 规范与推荐标准 1. 界面gui方面的前后端分离重大意义1 2. 业务逻辑也适当的迁移js化1 3. 常用分离方法2 3.1. 页面 ...

  2. Android Launcher分析和修改1——Launcher默认界面配置(default_workspace)

    最近工作都在修改Launcher,所以打算把分析源码和修改源码的过程记录下来,最近会写一些关于Launcher的分析和修改博文.因为我是修改4.0.3的Launcher,所以后面文章里面的Launch ...

  3. 【iCore4 双核心板_ARM】例程六:IWDG看门狗实验——复位ARM

    实验原理: STM32内部包含独立看门狗,通过看门狗可以监控程序远行,程序运行错误时, 未在规定时间内喂狗,自动复位ARM.本实验通过按键按下,停止喂狗,制造程序运行 错误,从而产生复位. 核心代码: ...

  4. 为什么watch机制不是银弹?

    几乎所有构建系统都选择使用watch机制来解决开发过程中需要反复生成构建后文件的问题,但在watch机制下,长期以来我们必须忍受修改完代码,保存完代码必须喝口茶才能刷新看看效果的问题.在这里我们尝试探 ...

  5. uboot i2c 操作函数记录

    I2C 在 u-boot 上面,有直接操作 I2C 的函数 // drivers/i2c/i2c_core.c // 设置在哪个 I2C bus 上工作 276 int i2c_set_bus_num ...

  6. vs2013 error LNK2005 已经在***.obj中定义

    错误解决办法: 方法一: 中文 项目--属性 ---连接器---输入                               附加依赖项    空格Nafxcwd.lib Libcmtd.lib ...

  7. headfirst python 05, 06

    处理数据 with open('james.txt') as jaf: data = jaf.readLine() james = data.strip().split(',') #先去掉空格而否有, ...

  8. Java知多少(10)数据类型及变量

    Java 是一种“强类型”的语言,声明变量时必须指明数据类型.变量(variable)占据一定的内存空间.不同类型的变量占据不同的大小. Java中共有8种基本数据类型,包括4 种整型.2 种浮点型. ...

  9. Linux下MySQL5.7.18二进制包安装(无默认配置文件my_default.cnf)

    最新在学习MySQL,纯新手,对Linux了解的也不多,因为是下载的最新版的MySQL(MySQL5.7.18)二进制包,CentOS7.2下测试安装,方便以后折腾.大概步骤如下,安装删除反复折腾了几 ...

  10. 查看pip安装的Python库

    查看安装的库 pip list或者pip freeze 查看过时的库 pip list --outdated 批量更新的Python脚本 import pip from subprocess impo ...