条件变量:
  当一个线程互斥的访问某个变量时,它可能发现其他线程改变状态之前,它什么都做不了
例如:一个线程访问队列时,发现队列为空,它只能等待,直到其他线程将一个节点添加到队列中,这种情况就需要使用条件变量。

线程A:                                         线程B:

                                          改变n
int n=0                                          进入临界区
进入临界区

                                                  更改 n>0
等待 n>0(该线程进入临界区其他的线程无法运行)                    通知等待线程
操作n                                        退出临界区
退出临界区

注意:当一个线程进入临界区,等待n>0,其余的线程无法获取互斥量(同一个互斥量)进入临界区修改n,那么线程A就会一直等待。
就会出现死锁,所以我们引入了条件变量。条件变量要跟互斥量配合使用,一是因为多个线程都可以访问条件n>0;而是因为一个线程
对互斥量加锁,其他线程就无法获得互斥量修改n.所以条件变量一开始先解锁,那么线程就可以获得互斥量,修改n.也可以等待条件。

条件变量使用规范
  等待条件代码:
  pthread_mutex_lock(&mutex);
  while(条件为假)
  pthread_cond_wait(cond,mutex);
  修改条件
  pthread_mutex_unlock(&mutex);

给条件发送信号代码:
  pthread_mutex_lock(&mutex);
设置条件为真
  pthread_cond_signal(cond);
  pthread_mutex_unlock(&mutex);

通知条件成立
  int pthread_cond_signal(pthread_cond_t *cond);
等待条件成立
  int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);

while(1)
{
pthread_mutex_lock(&g_mutex);
//为何使用while而不是if
//被信号打断的话,一种pthread_cond_wait重启,就行没有发生一样,或者pthread_cond_wait可能被虚假唤醒,所以要用while再次判断条件。
while(nready==0)
{
pthread_cond_wait(&g_cond,&g_mutex);
}
--nready;
pthread_mutex_unlock(&g_mutex);
}

pthread_cond_wait(原语)内部进行的操作:
一、对g_mutex进行解锁(其他消费者线程可以进行等待,生产者线程也可以改变条件)

二、等待条件,直到其他线程向它发起通知
三、返回的时候对互斥量重新加锁

while(1)
{
pthread_mutex_lock(&g_mutex);
nready++;
if(nready>0)
pthread_cond_signal(&g_cond);//条件满足,发起通知
pthread_mutex_unlock(&g_mutex);
}
  pthread_cond_signal
            向第一个等待条件的线程发起通知,如果没有任何一个线程处于等待条件的状态,这个通知将被忽略
  pthread_cond_broadcast
            向所有的等待线程发起通知

用条件变量解决生产者、消费者问题(缓冲区无界,假定仓库无限大)

  1 #include<unistd.h>
2 #include<sys/types.h>
3 #include<fcntl.h>
4 #include<sys/stat.h>
5 #include<stdlib.h>
6 #include<stdio.h>
7 #include<errno.h>
8 #include <semaphore.h>
9 #include<pthread.h>
10 #define ERR_EXIT(m)\
11 do\
12 {\
13 perror(m);\
14 exit(EXIT_FAILURE);\
15 }while(0)
16 #define CONSUMERS_COUNT 2
17 #define PRODUCERS_COUNT 4
18
19 unsigned short in=0;
20 unsigned short out=0;
21 unsigned short produce_id=0;//当前正在消费的产品ID
22 unsigned short consume_id=0;//当前正在消费的产品ID
23
24 pthread_cond_t g_cond;
25 pthread_mutex_t g_mutex;
26 pthread_t g_thread[CONSUMERS_COUNT+PRODUCERS_COUNT ];
27
28 //消费者线程
29 int nready=0;//缓冲区没有产品
30 void* consume(void*arg)
31 {
32 int num=(int)arg;//线程编号
33
34 while(1)
35 {
36 pthread_mutex_lock(&g_mutex);
37 //当条件不成立,就一直等待。
38 while(nready==0)
39 {
40 printf("%d begin wait a condition...\n",num);
41 //跟互斥锁配合使用,先解锁,以便其他线程进入临界区修改条件,防止死锁。
42 pthread_cond_wait(&g_cond,&g_mutex);//在nready==0上等待。
43 //再加锁
44 }
45 //条件改变了
46 printf("%d end wait a condition...\n",num);
47 printf("%d begin consume product...\n",num);
48 --nready;//消费产品
49 pthread_mutex_unlock(&g_mutex);
50 sleep(1);
51 }
52 return NULL;
53 }
54 //生产者线程
55 void* produce(void*arg)
56 {
57 int num=(int)arg;
58
59 while(1)
60 {
61 pthread_mutex_lock(&g_mutex);
62 printf("%d begin produce product...\n",num);
63 nready++;//直接开始生产产品。
64 printf("%d end produce product...\n",num);
65 //条件成立,通知等待线程
66 pthread_cond_signal(&g_cond);
67 printf("%d signal \n",num);//某个线程发起通知
68 pthread_mutex_unlock(&g_mutex);
69 sleep(1);
70 }
71 return NULL;
72 }
73 int main(void)
74 {
75 int i;
76 //初始化互斥量和条件变量
77 pthread_mutex_init(&g_mutex,NULL);
78 pthread_cond_init(&g_cond,NULL);
79 //创建消费者线程
80 for(i=0;i<CONSUMERS_COUNT;i++)
81 {
82 pthread_create(&g_thread[i],NULL,consume,(void*)i);//产生了段错误.我们传递的是值,所以int num=(int)arg 而不是int num=*(int*)arg
83 }
84
85 sleep(1);//以便消费者进入等待
86 //创建生产者线程
87 for(i=0;i<PRODUCERS_COUNT;i++)
88 {
89 pthread_create(&g_thread[i+CONSUMERS_COUNT],NULL,produce,(void*)i);
90 }
91 //等待线程退出
92 for(i=0;i<CONSUMERS_COUNT+PRODUCERS_COUNT;i++)
93 {
94 pthread_join(g_thread[i],NULL);
95 }
96
97 pthread_cond_destroy(&g_cond);
98 pthread_mutex_destroy(&g_mutex);
99 return 0;
100 }

POSIX条件变量的更多相关文章

  1. Linux多线程实践(8) --Posix条件变量解决生产者消费者问题

    Posix条件变量 int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr); int pthread_co ...

  2. posix 条件变量与互斥锁 示例生产者--消费者问题

    一.posix 条件变量 一种线程间同步的情形:线程A需要等某个条件成立才能继续往下执行,现在这个条件不成立,线程A就阻塞等待,而线程B在执行过程中使这个条件成立了,就唤醒线程A继续执行. 在pthr ...

  3. Linux多线程实践(六)使用Posix条件变量解决生产者消费者问题

    前面的一片文章我们已经讲过使用信号量解决生产者消费者问题.那么什么情况下我们须要引入条件变量呢? 这里借用  http://www.cnblogs.com/ngnetboy/p/3521547.htm ...

  4. linux网络编程之posix条件变量

    今天来学习posix的最后一个相关知识----条件变量,言归正传. 下面用一个图来进一步描述条件变量的作用: 为什么呢? 这实际上可以解决生产者与消费者问题,而且对于缓冲区是无界的是一种比较理解的解决 ...

  5. 第四十章 POSIX条件变量

    条件变量 当一个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了 例如一个线程访问队列时,发现队列为空,它只能等待,只到其它线程将一个节点添加到队列中.这种情况就需要用到条件 ...

  6. linux网络编程-posix条件变量(40)

    举一个列子来说明条件变量: 假设有两个线程同时访问全局变量n,初始化值是0, 一个线程进入临界区,进行互斥操作,线程当n大于0的时候才执行下面的操作,如果n不大于0,该线程就一直等待. 另外一个线程也 ...

  7. Linux互斥锁、条件变量和信号量

    Linux互斥锁.条件变量和信号量  来自http://kongweile.iteye.com/blog/1155490 http://www.cnblogs.com/qingxia/archive/ ...

  8. 并发编程(一): POSIX 使用互斥量和条件变量实现生产者/消费者问题

    boost的mutex,condition_variable非常好用.但是在Linux上,boost实际上做的是对pthread_mutex_t和pthread_cond_t的一系列的封装.因此通过对 ...

  9. 进程间通信机制(管道、信号、共享内存/信号量/消息队列)、线程间通信机制(互斥锁、条件变量、posix匿名信号量)

    注:本分类下文章大多整理自<深入分析linux内核源代码>一书,另有参考其他一些资料如<linux内核完全剖析>.<linux c 编程一站式学习>等,只是为了更好 ...

随机推荐

  1. 如何解决Win7,win8无法使用DOS的Debug:

    如何解决Win7,win8无法使用DOS的Debug: 安装dosbox 将含有程序link,masm,edit,debug的文件夹masm放到d盘根目录 打开dosbox,输入mount c d:\ ...

  2. day20 Pyhton学习 面向对象-类与类之间的关系

    一.类与类之间的依赖关系 class Elphant: def __init__(self, name): self.name = name def open(self, ref): print(&q ...

  3. 【学习笔记】扩展卢卡斯定理 exLucas

    引子 求 \[C_n^m\ \text{mod}\ p \] 不保证 \(p\) 是质数. 正文 对于传统的 Lucas 定理,必须要求 \(p\) 是质数才行.若 \(p\) 不一定是质数,则需要扩 ...

  4. spring boot:shardingsphere+druid整合seata分布式事务(spring boot 2.3.3)

    一,shardingshpere为什么要整合seata? 分库分表是数据库扩展中最常用的处理方法, shardingshpere作为使用最广泛的分表中间件, 如果不支持分布式事务,则它的数据一致性就会 ...

  5. JavaScript数字与字母相互转换

    数字 转换为 字母: const num = 'a'.charCodeAt() // num = 97 字母 转换为 数字: var str = String.fromCharCode(97) // ...

  6. concurrenthasmap

    concur'renthashmap java1.7 hashMap在单线程中使用大大提高效率,在多线程的情况下使用hashTable来确保安全.hashTable中使用synchronized关键字 ...

  7. sangforEDR 任意命令执行

    EDR 使用范围 由于只有POC 没有详细细节.暂时不知道具体细节. 部分EDR 已经完成升级,不存在该漏洞. POC https://XXX:8081/tool/log/c.php?strip_sl ...

  8. viewPager删除缓存fragment

    fragment结合viewpager会缓存fragment在内存,除非退出程序,想要不退出程序情况下刷新fragment页面,就要删除缓存; public class MainActivity ex ...

  9. python接口自动化测试--批量读取数据

    为了便于维护,python接口自动化测试用例可以利用xlrd模块读取excal表格进行数据分离.我们可以利用xlrd模块的row_values()和cell_value()两种方法读取Excal表格. ...

  10. 世界碰撞算法原理和总结(sat gjk)

    序言 此文出于作者的想法,从各处文章和论文中,总结和设计项目中碰撞结构处理方法.如有其它见解,可以跟作者商讨.(杨子剑,zijian_yang@yeah.net). 在一个世界中,有多个物体,物体可以 ...