posix 条件变量与互斥锁 示例生产者--消费者问题
一、posix 条件变量
一种线程间同步的情形:线程A需要等某个条件成立才能继续往下执行,现在这个条件不成立,线程A就阻塞等待,而线程B在执行过程中使这个条件成立了,就唤醒线程A继续执行。
在pthread库中通过条件变量(Condition
Variable)来阻塞等待一个条件,或者唤醒等待这个条件的线程。Condition
Variable用pthread_cond_t类型的变量表示,和Mutex的初始化和销毁类似,pthread_cond_init函数初始化一个Condition
Variable,attr参数为NULL则表示缺省属性,pthread_cond_destroy函数销毁一个Condition
Variable。如果ConditionVariable是静态分配的,也可以用宏定义PTHEAD_COND_INITIALIZER初始化,相当于用pthread_cond_init函数初始化并且attr参数为NULL。
一个Condition Variable总是和一个Mutex搭配使用的。一个线程可以调用pthread_cond_wait在一个Condition Variable上阻塞等待,这个函数做以下三步操作:
1. 释放Mutex
2. 阻塞等待
3. 当被唤醒时,重新获得Mutex并返回
注意:3个操作是原子性的操作,之所以一开始要释放Mutex,是因为需要让其他线程进入临界区去更改条件,或者也有其他线程需要进入临界区等待条件。
一个线程可以调用 pthread_cond_signal 唤醒在某个Condition Variable上等待的第一个线程,也可以调用 pthread_cond_broadcast 唤醒在这个Condition Variable上等待的所有线程。
上面的函数具体可以man 一下。
二、条件变量使用规范
(一)、等待条件代码
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);
假设第一段用于消费者线程,第二段用于生产者线程。为什么消费者线程要用while 而不是if 就可以呢?在man pthread_cond_wait 有一句:If
a signal is delivered to a thread waiting for a condition variable,
upon return from the signal handler
the thread resumes waiting for the condition variable as if it was not
interrupted, or it shall return zero due to spurious wakeup.
即是说如果正在等待条件变量的一个线程收到一个信号,从信号处理函数返回的时候线程应该重新等待条件变量就好象没有被中断一样,或者被虚假地唤醒返回0。如果是上述情形,那么其实条件并未被改变,那么此时如果没有继续判断一下条件的真假就继续向下执行的话,修改条件将会出现问题,所以需要使用while
循环再判断一下,如果条件还是为假必须继续等待。
注:在多处理器系统中,pthread_cond_signal 可能会唤醒多个等待条件的线程,这也是一种spurious wakeup。
当生产者线程较多,即生产得比较快,在这边假设是无界的缓冲区(比如链表),可以不停地生产,使用pthread_cond_signal
发出通知的时候,如果此时没有消费者线程在等待条件,那么这个通知将被丢弃,但也不影响整体代码的执行,没有消费者线程在等待,说明产品资源充足,即while
判断失败,不会进入等待状态,直接消费产品(即修改条件)。
三、生产者消费者问题
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
#include <unistd.h>
#include <sys/types.h> #include <pthread.h> #include <semaphore.h> #include <stdlib.h> #define ERR_EXIT(m) \ #define CONSUMERS_COUNT 2 pthread_mutex_t g_mutex; pthread_t g_thread[CONSUMERS_COUNT + PRODUCERS_COUNT]; int nready = 0; void *consume(void *arg) printf("%d end wait a condtion ...\n", num); void *produce(void *arg) int main(void) pthread_mutex_init(&g_mutex, NULL); for (i = 0; i < CONSUMERS_COUNT; i++) sleep(1); for (i = 0; i < PRODUCERS_COUNT; i++) for (i = 0; i < CONSUMERS_COUNT + PRODUCERS_COUNT; i++) pthread_mutex_destroy(&g_mutex); return 0; |
在上面程序中,++nready 就当作是生产产品了,--nready就当作是消费产品了,跟前面文章所不同的是,这里没有缓冲区大小的概念,可以当作是无界缓冲区,生产者可以一直生产,但消费者只有当有产品的时候才能消费,否则就得等待,等待结束的条件就是nready
> 0;上面也说过当生产得比较快(生产者线程多)的时候,也有可能消费者线程一直不存在等待的状态,因为nready 的值很大,即产品资源很多。现在设置的是2个消费者线程和1个生产者线程,所以动态输出来看一般是2个消费者线程轮流等待。
参考:
《linux c 编程一站式学习》
《UNP》
posix 条件变量与互斥锁 示例生产者--消费者问题的更多相关文章
- posix 匿名信号量与互斥锁 示例生产者--消费者问题
一.posix 信号量 信号量的概念参见这里.前面也讲过system v 信号量,现在来说说posix 信号量. system v 信号量只能用于进程间同步,而posix 信号量除了可以进程间同步,还 ...
- POSIX信号量与互斥锁实现生产者消费者模型
posix信号量 Link with -lpthread. sem_t *sem_open(const char *name, int oflag);//打开POSIX信号量 sem_t *sem_o ...
- Linux Qt使用POSIX多线程条件变量、互斥锁(量)
今天团建,但是文章也要写.酒要喝好,文要写美,方为我辈程序员的全才之路.嘎嘎 之前一直在看POSIX的多线程编程,上个周末结合自己的理解,写了一个基于Qt的用条件变量同步线程的例子.故此来和大家一起分 ...
- 并发编程(二):分析Boost对 互斥量和条件变量的封装及实现生产者消费者问题
请阅读上篇文章<并发编程实战: POSIX 使用互斥量和条件变量实现生产者/消费者问题>.当然不阅读亦不影响本篇文章的阅读. Boost的互斥量,条件变量做了很好的封装,因此比" ...
- 并发编程入门(二):分析Boost对 互斥量和条件变量的封装及实现生产者消费者问题
请阅读上篇文章<并发编程实战: POSIX 使用互斥量和条件变量实现生产者/消费者问题>.当然不阅读亦不影响本篇文章的阅读. Boost的互斥量,条件变量做了很好的封装,因此比" ...
- 【转载】同步和互斥的POSIX支持(互斥锁,条件变量,自旋锁)
上篇文章也蛮好,线程同步之条件变量与互斥锁的结合: http://www.cnblogs.com/charlesblc/p/6143397.html 现在有这篇文章: http://blog.cs ...
- linux网络编程之posix条件变量
今天来学习posix的最后一个相关知识----条件变量,言归正传. 下面用一个图来进一步描述条件变量的作用: 为什么呢? 这实际上可以解决生产者与消费者问题,而且对于缓冲区是无界的是一种比较理解的解决 ...
- 第四十章 POSIX条件变量
条件变量 当一个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了 例如一个线程访问队列时,发现队列为空,它只能等待,只到其它线程将一个节点添加到队列中.这种情况就需要用到条件 ...
- linux网络编程-posix条件变量(40)
举一个列子来说明条件变量: 假设有两个线程同时访问全局变量n,初始化值是0, 一个线程进入临界区,进行互斥操作,线程当n大于0的时候才执行下面的操作,如果n不大于0,该线程就一直等待. 另外一个线程也 ...
随机推荐
- Android中intent如何传递自定义数据类型
转载自:http://www.cnblogs.com/GoAhead/archive/2012/07/16/2593868.html 大家好,好久不见,今天要给大家讲一下Android中Intent中 ...
- iOS开发-简单的图片查看器
现在你只要拿着手机,不管你Android还是iOS,新闻类的App不可避免都有一个功能就是图片查看,做个专题,查看一下内容,App Store中也有专门针对图片浏览的App,鉴于目前所知有限,无法做到 ...
- Longest Consecutive Sequence leetcode java
题目: Given an unsorted array of integers, find the length of the longest consecutive elements sequenc ...
- 集合 数组 定义 转换 遍历 Arrays API MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- jQuery练手:仿新浪微博图片文字列表淡进淡出上下滚动效果
1.效果及功能说明 仿新浪微博图片文字列表上下淡进淡出间歇上下滚动 2.实现原理 首先要设定div内只能显示4个图片那么多出来的图片会自动隐藏然后在给图片添加一个动画的事件让他们可以滚动的播放出来上下 ...
- 如何在Linux中用命令行工具管理KVM虚拟环境
第一步: 配置存储池 Virsh命令行工具是一款管理virsh客户域的用户界面,它能在命令行中运行所给的命令以及它的参数,我们要用它给我们的KVM环境创建存储池,想知道关于这个工具的更多信息,用以下这 ...
- 【SQLite】 C#中操作SQlite
简介 SQLite是轻量级数据库,具体的介绍请参考官网(SQLite官网).在WinForm的项目中需要采用独立的数据库访问,可在断网单机上使用,所以选择了SQLite! 使用 主要针对C#项目(Wi ...
- GetProcAddress 使用注意事项
使用 GetProcAddress Function 时,有以下几点需要特别留意: 1. 第二个参数类型是 LPCSTR,不是 : 2. 用 __declspec(dllexport),按 C 名称修 ...
- Servlet学习笔记(七)—— 自己定义过滤器的编写改进:自己定义实现FilterChain
笔记六中实现了三种过滤器:字符编码过滤.登录权限过滤.敏感词过滤,可是有个缺陷就是,限定了过滤顺序,而不能实现先进行request过滤.最后response过滤,而且中间几项过滤的顺序不能动态改变.所 ...
- 使用sed进行文字替换
范式: sed -i "s/查找内容/替换后内容/g" `grep 查找内容 -rl 查找开始路径` 例子: #sed -i "s/abc/ABC/g" `gr ...