前言

在上一篇文章《深入理解Linux 条件变量1:使用场景、接口说明》我们简单介绍了条件变量的使用场景以及相关接口,正如大神linus所说:talk is cheap,show me the code,本文我们就使用条件变量机制,来实现一个【生产,消费模型】。

生产-消费线程示例demo

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>/** Get offset of a member variable.** @param[in]   type     the type of the struct this is embedded in.* @param[in]   member   the name of the variable within the struct.*/
#define aos_offsetof(type, member)   ((size_t)&(((type *)0)->member))/** Get the struct for this entry.** @param[in]   ptr     the list head to take the element from.* @param[in]   type    the type of the struct this is embedded in.* @param[in]   member  the name of the variable within the struct.*/
#define aos_container_of(ptr, type, member)\((type *) ((char *) (ptr) - aos_offsetof(type, member)))/** Get the struct for this entry.* @param[in]   ptr     the list head to take the element from.* @param[in]   type    the type of the struct this is embedded in.* @param[in]   member  the name of the variable within the struct.*/
#define list_entry(ptr, type, member)\aos_container_of(ptr, type, member)typedef struct slist_s {struct slist_s *next;
} slist_t;static inline void slist_add(slist_t *node, slist_t *head)
{node->next = head->next;head->next = node;
}static inline void slist_add_tail(slist_t *node, slist_t *head)
{while (head->next) {head = head->next;}slist_add(node, head);
}static inline void slist_del(slist_t *node, slist_t *head)
{while (head->next) {if (head->next == node) {head->next = node->next;break;}head = head->next;}
}static inline int slist_empty(const slist_t *head)
{return !head->next;
}static inline void slist_init(slist_t *head)
{head->next = 0;
}/** Iterate over list of given type safe against removal of list entry.** @param[in]   queue   the head for your list.* @param[in]   tmp     the type * to use as a temp.* @param[in]   node    the type * to use as a loop cursor.* @param[in]   type    the type of the struct this is embedded in.* @param[in]   member  the name of the slist_t within the struct.*/
#define slist_for_each_entry_safe(queue, tmp, node, type, member)\for (node = aos_container_of((queue)->next, type, member),\tmp = (queue)->next ? (queue)->next->next : NULL;\&node->member;\node = aos_container_of(tmp, type, member), tmp = tmp ? tmp->next : tmp)// 自定义消息结构
typedef struct msg{slist_t list;int data;
} msg_t;pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_hasProduct = PTHREAD_COND_INITIALIZER;
slist_t g_msg_head = {NULL};void *th_producer(void *arg)
{int cnt = 0;msg_t *new_node = NULL;pthread_detach(pthread_self());while(1){// 申请一个消息节点,初始化链表元素,并且对数据赋值new_node = (msg_t *)malloc(sizeof(msg_t));new_node->data = cnt++;slist_init(&new_node->list);pthread_mutex_lock(&mutex);// 将节点数据添加到消息链表中slist_add_tail(&new_node->list, &g_msg_head);pthread_mutex_unlock(&mutex);// 发送信号到条件变量pthread_cond_signal(&cond_hasProduct);usleep(100000);}printf("thread producer exit.\n");return (void *)0;
}void *th_consumer(void *arg)
{char *name = (char *)arg;msg_t *pos = NULL;slist_t *tmp;while(1){pthread_mutex_lock(&mutex);while(slist_empty(&g_msg_head)){// 等待条件变量状态变化通知pthread_cond_wait(&cond_hasProduct, &mutex);}// 取消息队列的首个 节点消息slist_for_each_entry_safe(&g_msg_head, tmp, pos, msg_t, list){printf("------- [%s] get %d --------\n", name, pos->data);slist_del(&pos->list, &g_msg_head);free(pos);pos = NULL;break;}pthread_mutex_unlock(&mutex);}return NULL;
}int main(void)
{pthread_t pid, cid, cid2, cid3;static const char *th_consum1 = "th_consum1";static const char *th_consum2 = "th_consum2";static const char *th_consum3 = "th_consum3";slist_init(&g_msg_head);pthread_create(&pid, NULL, th_producer, NULL);sleep(2);printf("start create consumer thread.\n");pthread_create(&cid, NULL, th_consumer, (void *)th_consum1);pthread_create(&cid2, NULL, th_consumer, (void *)th_consum2);pthread_create(&cid3, NULL, th_consumer, (void *)th_consum3);pthread_join(pid, NULL);pthread_join(cid, NULL);pthread_join(cid2, NULL);pthread_join(cid3, NULL);return 0;
}

程序运行效果如下:

------- [th_consum3] get 0 --------
------- [th_consum1] get 1 --------
------- [th_consum1] get 2 --------
------- [th_consum1] get 3 --------
------- [th_consum1] get 4 --------
------- [th_consum1] get 5 --------
------- [th_consum1] get 6 --------
------- [th_consum1] get 7 --------
------- [th_consum1] get 8 --------
------- [th_consum1] get 9 --------
------- [th_consum1] get 10 --------
------- [th_consum3] get 11 --------
------- [th_consum2] get 12 --------
------- [th_consum1] get 13 --------
------- [th_consum3] get 14 --------
------- [th_consum2] get 15 --------
------- [th_consum1] get 16 --------

从运行效果可以看出,上述示例代码实现了一种典型的生产-消费框架,上述示例中创建了1个生产线程,3个消费线程,3个消费线程能够随机的消费生产数据。

课后作业

  1. 上述示例代码中,th_producer生产线程中,pthread_cond_signal为什么要在pthread_mutex_unlock后面,而不是在它之前?
  2. 在th_consumer线程中,为什么使用while(slist_empty(&g_msg_head)),而不是if(slist_empty(&g_msg_head)) ?
  3. 在th_consumer线程中,pthread_cond_wait之前为什么要先pthread_mutex_lock?
  4. pthread_cond_wait 阻塞了,这个时候 mutex 互斥锁也已经lock了,生产线程还能不能拿到mutex?
  5. 在main函数中,我们先创建了生产线程,并且等待了2s才创建消费线程,而生产线程每100ms生产一次数据,然后就调用pthread_cond_signal 通知条件变量,那么是不是前2s发送的信号给条件变量都丢了?pthread_cond_wait就等不到前2s的通知了?

这些问题,每个问题都涉及到条件变量的关键知识点,我们在后面的文章会对这些问题进行一一分析并回答。

深入理解Linux 条件变量2:使用条件变量实现[生产-消费]框架相关推荐

  1. 深入理解Linux 条件变量3:条件变量为什么要配合着锁使用?

    在上一篇文章<深入理解Linux 条件变量2:使用条件变量实现[生产-消费]框架>中,我们通过示例代码演示了条件变量的使用.从条件变量的API接口中我们很容易发现,条件变量必须配合着互斥锁 ...

  2. 理解 Linux 条件变量

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/cheungmine/article/details/37317429 理解 Linux 条件变量 1 ...

  3. Linux Qt使用POSIX多线程条件变量、互斥锁(量)

    今天团建,但是文章也要写.酒要喝好,文要写美,方为我辈程序员的全才之路.嘎嘎 之前一直在看POSIX的多线程编程,上个周末结合自己的理解,写了一个基于Qt的用条件变量同步线程的例子.故此来和大家一起分 ...

  4. 很详细、很移动的Linux makefile教程:介绍,总述,书写规则,书写命令,使用变量,使用条件推断,使用函数,Make 的运行,隐含规则 使用make更新函数库文件 后序...

    很详细.很移动的Linux makefile 教程 内容如下: Makefile 介绍 Makefile 总述 书写规则 书写命令 使用变量 使用条件推断 使用函数 make 的运行 隐含规则 使用m ...

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

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

  6. Linux系统编程---17(条件变量及其函数,生产者消费者条件变量模型,生产者与消费者模型(线程安全队列),条件变量优点,信号量及其主要函数,信号量与条件变量的区别,)

    条件变量 条件变量本身不是锁!但它也可以造成线程阻塞.通常与互斥锁配合使用.给多线程提供一个会合的场所. 主要应用函数: pthread_cond_init 函数 pthread_cond_destr ...

  7. Linux多线程开发-线程同步-条件变量pthread_cond_t

    1.条件变量的概念 一个线程A的执行需要另一个线程B来唤醒,否则A挂起等待.线程B可以产生线程A继续执行的信号.条件变量常用在共享数据状态变化的场景中,例如:生产则和消费者问题.POSIX线程库提供了 ...

  8. linux shell 流程控制(条件if,循环【for,while】,选择【case】语句实例 --转载

    http://www.cnblogs.com/chengmo/archive/2010/10/14/1851434.html nux shell有一套自己的流程控制语句,其中包括条件语句(if),循环 ...

  9. C语言里if语句变量作为判断条件,C语言教学(九-上)if else判断语句

    原标题:C语言教学(九-上)if else判断语句 今天讲if else判断语句,简单理解就是进行条件判断,如果条件达到则执行if 里或else里的语句.先来看if. if的写法和for差不多,就是不 ...

最新文章

  1. Hhadoop-2.7.0中HDFS写文件源码分析(二):客户端实现(1)
  2. Codeforce1311B. WeirdSort (冒泡排序)
  3. Nand Flash与Nor Flash
  4. java 递归_采用递归算法求解迷宫问题(Java版) | 附代码+视频
  5. MySQL 在高并发下的 订单撮合 系统使用 共享锁 与 排他锁 保证数据一致性
  6. 【Java】什么是多态?多态的实现机制是什么?
  7. 研发管理三部曲——贰 · 研发管理应该干什么
  8. java以正确的方式停止线程
  9. 实现异步加载js文件及加载完成后回调
  10. Linux文本处理之awk
  11. 关于java前端与后端的技术和工资对比!
  12. C语言--求质数(详解)(筛选求质数)
  13. 记录几种敏捷开发应用的工具
  14. java拍照控件焦距问题,监控摄像头镜头焦距计算方法
  15. 崩溃日志保存本地log,服务器上传
  16. 第17节 三个败家子(17)——少侠孙坚
  17. C++学习笔记——安装visual studio 2013
  18. 番茄时钟(提升专注力,减少中断)- 番茄工作法
  19. 什么是含源一端口网络_二端口网络
  20. 基于分水岭算法和机载激光雷达点云三维空间分布分析的单棵树分割方法

热门文章

  1. 实验三 mysql数据库与表的创建_实验二 数据库和表的创建与管理
  2. 我敢打赌你一定不知道的软件测试基础知识整理
  3. python开源项目贡献_为开源项目做出第一笔贡献
  4. LAMP源码环境搭建
  5. android 修改充电图标,更换图标、修改充电音...这个软件把iPhone玩成了安卓
  6. mysql fastdfs_FastDFS监控系统Fastdfs-zyc配置
  7. 【懒懒的Python学习笔记十】
  8. Fluent 操作入门实例-从建模到计算结果可视化
  9. Github推荐--PC端下载bilibili视频
  10. IDEA 配置 maven