“生产者——消费者”问题是Linux多线程编程中的经典问题,主要是利用信号量处理线程间的同步和互斥问题。

“生产者——消费者”问题描述如下:

有一个有限缓冲区(这里用有名管道实现 FIFO 式缓冲区)和两个线程:生产者和消费者,它们分别不停地把产品放入缓冲区中拿走产品。一个生产者在缓冲区满的时候必须等待,一个消费者在缓冲区空的时候也不IXUS等待。另外,因为缓冲区是临界资源,所以生产者和消费者之间必须互斥进行。它们之间的关系如下:

这里要求使用有名管道来模拟有限缓冲区,并用信号量来解决“生产者——消费者”问题中的同步和互斥问题。

1、信号量分析

这里使用3个信号量,其中两个信号量 avail 和 full 分别用于解决生产者和消费者线程之间的互斥问题。其中avail 表示缓冲区的空单元数,初始值为N;full 表示缓冲区非空单元数,初始值为 0 ; mutex 是互斥信号量 ,初始值为 1(当然也可以用互斥锁来实现互斥操作)。

2、画出流程图

3、编写代码

本实验的代码中缓冲区拥有3个单元,每个单元为5个字节。为了尽量体现每个信号量的意义,在程序中生产过程和消费过程是随机(采取0~5s 的随机事件间隔)进行的,而且生产者的速度比消费者的速度平均快两倍左右。生产者一次生产一个单元的产品(放入hello字符串),消费者一次消费一个单元的产品。

[cpp] view plaincopy
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <pthread.h>
  6. #include <sys/types.h>
  7. #include <time.h>
  8. #include <fcntl.h>
  9. #include <semaphore.h>
  10. #include <sys/ipc.h>
  11. #include <errno.h>
  12. #define MYFIFO "myfifo"
  13. #define BUFFER_SIZE 3
  14. #define UNIT_SIZE 5
  15. #define RUN_TIME 30
  16. #define DELAY_TIME_LEVELS 5.0
  17. void *producer(void *arg);
  18. void *customer(void *arg);
  19. int fd;
  20. time_t end_time;
  21. sem_t mutex,full,avail;
  22. int main()
  23. {
  24. int ret;
  25. pthread_t thrd_prd_id,thrd_cst_id;
  26. srand(time(NULL));
  27. end_time = time(NULL) + RUN_TIME;
  28. /*创建有名管道*/
  29. if((mkfifo(MYFIFO,0644) < 0) && (errno != EEXIST))
  30. {
  31. perror("mkfifo error!");
  32. exit(-1);
  33. }
  34. /*打开管道*/
  35. fd = open(MYFIFO,O_RDWR);
  36. if(fd == -1)
  37. {
  38. perror("open fifo error");
  39. exit(-1);
  40. }
  41. /*初始化互斥信号量为1*/
  42. ret = sem_init(&mutex,0,1);
  43. /*初始化avail信号量为 N */
  44. ret += sem_init(&avail,0,BUFFER_SIZE);
  45. /*初始化full信号量为0*/
  46. ret += sem_init(&full,0,0);
  47. if(ret != 0)
  48. {
  49. perror("sem_init error");
  50. exit(-1);
  51. }
  52. /*创建两个线程*/
  53. ret = pthread_create(&thrd_prd_id,NULL,producer,NULL);
  54. if(ret != 0)
  55. {
  56. perror("producer pthread_create error");
  57. exit(-1);
  58. }
  59. ret = pthread_create(&thrd_cst_id,NULL,customer,NULL);
  60. if(ret != 0)
  61. {
  62. perror("customer pthread_create error");
  63. exit(-1);
  64. }
  65. pthread_join(thrd_prd_id,NULL);
  66. pthread_join(thrd_cst_id,NULL);
  67. close(fd);
  68. unlink(MYFIFO);
  69. return 0;
  70. }
  71. void *producer(void *arg) //生产者线程
  72. {
  73. int real_write;
  74. int delay_time;
  75. while(time(NULL) < end_time)
  76. {
  77. delay_time = (int)(rand() * DELAY_TIME_LEVELS/RAND_MAX/2.0) + 1;
  78. sleep(delay_time);
  79. /*P操作信号量avail和mutex*/
  80. sem_wait(&avail);
  81. sem_wait(&mutex);
  82. printf("\nproducer have delayed %d seconds\n",delay_time);
  83. /*生产者写入数据*/
  84. if((real_write = write(fd,"hello",UNIT_SIZE)) == -1)
  85. {
  86. if(errno == EAGAIN)
  87. {
  88. printf("The buffer is full,please wait for reading!\n");
  89. }
  90. }
  91. else
  92. {
  93. printf("producer writes %d bytes to the FIFO\n",real_write);
  94. printf("Now,the buffer left %d spaces!\n",avail);
  95. }
  96. /*V操作信号量full 和 mutex*/
  97. sem_post(&full);
  98. sem_post(&mutex);
  99. }
  100. pthread_exit(NULL);
  101. }
  102. void *customer(void *arg) //消费者线程
  103. {
  104. unsigned char read_buffer[UNIT_SIZE];
  105. int real_read;
  106. int delay_time;
  107. while(time(NULL) < end_time)
  108. {
  109. delay_time = (int)(rand() * DELAY_TIME_LEVELS/RAND_MAX/2.0) + 1;
  110. sleep(delay_time);
  111. sem_wait(&full); //P操作信号量full和mutex
  112. sem_wait(&mutex);
  113. memset(read_buffer,0,UNIT_SIZE);
  114. printf("\nCustomer have delayed %d seconds\n",delay_time);
  115. if((real_read = read(fd,read_buffer,UNIT_SIZE)) == -1)
  116. {
  117. if(errno == EAGAIN)
  118. {
  119. printf("The buffer is empty,please wait for writing!\n");
  120. }
  121. }
  122. else
  123. {
  124. printf("customer reads %d bytes from the FIFO\n",real_read);
  125. }
  126. sem_post(&avail); //V操作信号量 avail 和 mutex
  127. sem_post(&mutex);
  128. }
  129. pthread_exit(NULL);
  130. }

执行结果如下:

[cpp] view plaincopy
  1. fs@ubuntu:~/qiang/pthread$ ./cust_prod
  2. producer have delayed 2 seconds
  3. producer writes 5 bytes to the FIFO
  4. Now,the buffer left 2 spaces!
  5. Customer have delayed 2 seconds
  6. customer reads 5 bytes from the FIFO
  7. producer have delayed 2 seconds
  8. producer writes 5 bytes to the FIFO
  9. Now,the buffer left 2 spaces!
  10. Customer have delayed 2 seconds
  11. customer reads 5 bytes from the FIFO
  12. producer have delayed 2 seconds
  13. producer writes 5 bytes to the FIFO
  14. Now,the buffer left 2 spaces!
  15. Customer have delayed 2 seconds
  16. customer reads 5 bytes from the FIFO
  17. producer have delayed 1 seconds
  18. producer writes 5 bytes to the FIFO
  19. Now,the buffer left 2 spaces!
  20. Customer have delayed 2 seconds
  21. customer reads 5 bytes from the FIFO
  22. producer have delayed 1 seconds
  23. producer writes 5 bytes to the FIFO
  24. Now,the buffer left 2 spaces!
  25. Customer have delayed 3 seconds
  26. customer reads 5 bytes from the FIFO
  27. producer have delayed 3 seconds
  28. producer writes 5 bytes to the FIFO
  29. Now,the buffer left 2 spaces!
  30. producer have delayed 1 seconds
  31. producer writes 5 bytes to the FIFO
  32. Now,the buffer left 1 spaces!
  33. Customer have delayed 2 seconds
  34. customer reads 5 bytes from the FIFO
  35. Customer have delayed 1 seconds
  36. customer reads 5 bytes from the FIFO
  37. producer have delayed 3 seconds
  38. producer writes 5 bytes to the FIFO
  39. Now,the buffer left 2 spaces!
  40. Customer have delayed 1 seconds
  41. customer reads 5 bytes from the FIFO
  42. producer have delayed 2 seconds
  43. producer writes 5 bytes to the FIFO
  44. Now,the buffer left 2 spaces!
  45. Customer have delayed 2 seconds
  46. customer reads 5 bytes from the FIFO
  47. producer have delayed 1 seconds
  48. producer writes 5 bytes to the FIFO
  49. Now,the buffer left 2 spaces!
  50. Customer have delayed 2 seconds
  51. customer reads 5 bytes from the FIFO
  52. producer have delayed 1 seconds
  53. producer writes 5 bytes to the FIFO
  54. Now,the buffer left 2 spaces!
  55. producer have delayed 1 seconds
  56. producer writes 5 bytes to the FIFO
  57. Now,the buffer left 1 spaces!
  58. Customer have delayed 2 seconds
  59. customer reads 5 bytes from the FIFO
  60. producer have delayed 2 seconds
  61. producer writes 5 bytes to the FIFO
  62. Now,the buffer left 1 spaces!
  63. Customer have delayed 3 seconds
  64. customer reads 5 bytes from the FIFO
  65. Customer have delayed 1 seconds
  66. customer reads 5 bytes from the FIFO
  67. producer have delayed 3 seconds
  68. producer writes 5 bytes to the FIFO
  69. Now,the buffer left 2 spaces!
  70. producer have delayed 1 seconds
  71. producer writes 5 bytes to the FIFO
  72. Now,the buffer left 1 spaces!
  73. Customer have delayed 2 seconds
  74. customer reads 5 bytes from the FIFO
  75. Customer have delayed 1 seconds
  76. customer reads 5 bytes from the FIFO
  77. producer have delayed 3 seconds
  78. producer writes 5 bytes to the FIFO
  79. Now,the buffer left 2 spaces!
  80. Customer have delayed 2 seconds
  81. customer reads 5 bytes from the FIFO
  82. producer have delayed 2 seconds
  83. producer writes 5 bytes to the FIFO
  84. Now,the buffer left 2 spaces!
  85. fs@ubuntu:~/qiang/pthread$

Linux 系统应用编程——多线程经典问题(生产者-消费者)相关推荐

  1. Linux系统及编程期末试题,《LINUX系统及其编程》考试试题及答案.doc

    <LINUX系统及其编程>考试试题及答案 <Linux系统及其编程>模拟练习参考答案 一.单项选择题 .Linux的根分区系统类型是 C . A. FAT16 B.FAT32 ...

  2. linux系统——Shell编程之变量解释

    linux系统--Shell编程之变量解释 - Shell能做什么 自动化批量系统初始化程序 (update,软件安装,时区设置,安全策略-) 自动化批量软件部署程序 (LAMP,LNMP,Tomca ...

  3. linux系统/网络编程

    经典数据: APUE:unix环境高级编程3版 linux系统编程手册 德 linux系统编程 oreily unix内核源码剖析 日 windows核心编程 linux系统开发模式: ssh远程登录 ...

  4. Linux 高性能服务器编程——多线程编程

    问题聚焦:     在简单地介绍线程的基本知识之后,主要讨论三个方面的内容:     1 创建线程和结束线程:     2 读取和设置线程属性:     3 线程同步方式:POSIX信号量,互斥锁和条 ...

  5. Linux 系统应用编程——进程间通信(下)

    在前面,我们学习了传统的进程间通信方式--无名管道(pipe).有名管道(fifo)和信号(signal). 下面我们来学习 System V  IPC 对象: 1.共享内存(share memory ...

  6. Linux 系统应用编程——进程基础

    一.Linux下多任务机制的介绍 Linux有一特性是多任务,多任务处理是指用户可以在同一时间内运行多个应用程序,每个正在执行的应用程序被称为一个任务. 多任务操作系统使用某种调度(shedule)策 ...

  7. linux系统io编程,Linux系统编程(1) —— 文件IO

    本文主要对Linux系统中文件I/O的基本操作进行说明. 在Linux系统编程中,对文件进行处理的流程,通常是: 打开文件 读写文件 关闭文件 Linux内核对每一个进程维护一个打开的文件列表, 该文 ...

  8. Linux学习-Linux系统及编程基础笔记

    useradd zhangsan passwd zhangsan visudo往/etc/sudoers文件中添加zhangsan #visudo 找到如下的行 root ALL=(ALL) ALL ...

  9. Linux 与 Python编程2021 经典函数实例 educoder实训

    第1关:递归函数 - 汉诺塔的魅力 编程要求 本关的编程任务是补全src/step1/recursive.py文件的代码,实现相应的功能.具体要求如下: 定义一个函数fact(n),实现的功能是对输入 ...

最新文章

  1. Android资源命名规范
  2. python3教程-Python3教程
  3. C#操作config文件
  4. tigervnc环境搭建
  5. 中文乱码翻译器在线翻译_如何将芬兰语翻译成中文?这两种方法你得会
  6. node.js 模块_如何创建Node JS可重用模块
  7. pbrt源码中用全主元消去法求矩阵逆的实现
  8. 最优化理论与凸优化到底是干嘛的?
  9. CMD如何进入C:WINDOWS\SYSTEM32
  10. 自动驾驶-LQR工程实现(调研)
  11. 从大数据的角度看 房价一定会下跌
  12. 谈EBOM 、PBOM 、MBOM 在PDM中的统一
  13. coffeescript html5,CoffeeScript函数
  14. UE4虚幻引擎4多人联机基础知识和客户端服务器通信机制详解
  15. 怎么压缩gif图大小,gif压缩到微信表情
  16. Java的学习之路Day08
  17. Pytorch实现CT图像正投影(FP)与反投影(FBP)的模块
  18. 力扣题目归类,顺序刷题不再难
  19. 【Beta】Scrum Meeting 4
  20. Android异步消息处理机制之looper机制

热门文章

  1. 雷军:互联网思维本质上就是群众路线
  2. yarn oom问题一例
  3. 在Eclipse中查看JDK类库的源代码
  4. 树莓派 zero linux,树莓派 zero基本调试
  5. 熊猫数据集_熊猫迈向数据科学的第三部分
  6. javascript创建类_如何在10分钟内使用JavaScript创建费用管理器
  7. 程序员如何学习更好的知识_如何保持学习并成为更好的程序员
  8. grafana 创建仪表盘_创建仪表盘前要问的三个问题
  9. 机器学习:分类_机器学习基础:K最近邻居分类
  10. 用原生js封装get方法