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

 “生产者——消费者”问题是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.   
  18. void *producer(void *arg);  
  19. void *customer(void *arg);  
  20.   
  21. int fd;  
  22. time_t end_time;  
  23. sem_t mutex,full,avail;  
  24.   
  25. int main()  
  26. {  
  27.     int ret;  
  28.     pthread_t thrd_prd_id,thrd_cst_id;  
  29.   
  30.     srand(time(NULL));  
  31.     end_time = time(NULL) + RUN_TIME;  
  32.   
  33.         /*创建有名管道*/  
  34.     if((mkfifo(MYFIFO,0644) < 0) && (errno != EEXIST))  
  35.     {  
  36.         perror("mkfifo error!");  
  37.         exit(-1);  
  38.     }  
  39.   
  40.         /*打开管道*/  
  41.     fd = open(MYFIFO,O_RDWR);  
  42.     if(fd == -1)  
  43.     {  
  44.         perror("open fifo error");  
  45.         exit(-1);  
  46.     }  
  47.   
  48.         /*初始化互斥信号量为1*/  
  49.     ret = sem_init(&mutex,0,1);  
  50.         /*初始化avail信号量为 N */  
  51.     ret += sem_init(&avail,0,BUFFER_SIZE);  
  52.     /*初始化full信号量为0*/  
  53.     ret += sem_init(&full,0,0);  
  54.   
  55.     if(ret != 0)  
  56.     {  
  57.         perror("sem_init error");  
  58.         exit(-1);  
  59.     }  
  60.   
  61.         /*创建两个线程*/  
  62.     ret = pthread_create(&thrd_prd_id,NULL,producer,NULL);  
  63.     if(ret != 0)  
  64.     {  
  65.         perror("producer pthread_create error");  
  66.         exit(-1);  
  67.     }  
  68.   
  69.     ret = pthread_create(&thrd_cst_id,NULL,customer,NULL);  
  70.     if(ret != 0)  
  71.     {  
  72.         perror("customer pthread_create error");  
  73.         exit(-1);  
  74.     }  
  75.   
  76.     pthread_join(thrd_prd_id,NULL);  
  77.     pthread_join(thrd_cst_id,NULL);  
  78.     close(fd);  
  79.     unlink(MYFIFO);  
  80.   
  81.     return 0;  
  82. }  
  83.   
  84. void *producer(void *arg) //生产者线程  
  85. {  
  86.     int real_write;  
  87.     int delay_time;  
  88.   
  89.     while(time(NULL) < end_time)  
  90.     {  
  91.         delay_time = (int)(rand() * DELAY_TIME_LEVELS/RAND_MAX/2.0) + 1;  
  92.         sleep(delay_time);  
  93.   
  94.                 /*P操作信号量avail和mutex*/  
  95.         sem_wait(&avail);  
  96.         sem_wait(&mutex);  
  97.         printf("\nproducer have delayed %d seconds\n",delay_time);  
  98.   
  99.                 /*生产者写入数据*/  
  100.         if((real_write = write(fd,"hello",UNIT_SIZE)) == -1)  
  101.         {  
  102.             if(errno == EAGAIN)  
  103.             {  
  104.                 printf("The buffer is full,please wait for reading!\n");  
  105.             }  
  106.         }  
  107.         else  
  108.         {  
  109.             printf("producer writes %d bytes to the FIFO\n",real_write);          
  110.             printf("Now,the buffer left %d spaces!\n",avail);  
  111.         }  
  112.                 /*V操作信号量full 和 mutex*/  
  113.         sem_post(&full);  
  114.         sem_post(&mutex);  
  115.     }  
  116.     pthread_exit(NULL);  
  117. }  
  118.   
  119. void *customer(void *arg) //消费者线程  
  120. {  
  121.     unsigned char read_buffer[UNIT_SIZE];  
  122.     int real_read;  
  123.     int delay_time;  
  124.   
  125.     while(time(NULL) < end_time)  
  126.     {  
  127.         delay_time = (int)(rand() * DELAY_TIME_LEVELS/RAND_MAX/2.0) + 1;  
  128.         sleep(delay_time);  
  129.   
  130.         sem_wait(&full); //P操作信号量full和mutex  
  131.         sem_wait(&mutex);  
  132.         memset(read_buffer,0,UNIT_SIZE);  
  133.         printf("\nCustomer have delayed %d seconds\n",delay_time);  
  134.   
  135.         if((real_read = read(fd,read_buffer,UNIT_SIZE)) == -1)  
  136.         {  
  137.             if(errno == EAGAIN)  
  138.             {  
  139.                 printf("The buffer is empty,please wait for writing!\n");  
  140.             }  
  141.         }  
  142.         else  
  143.         {  
  144.             printf("customer reads %d bytes from the FIFO\n",real_read);          
  145.         }  
  146.   
  147.         sem_post(&avail); //V操作信号量 avail 和 mutex  
  148.         sem_post(&mutex);         
  149.     }  
  150.   
  151.     pthread_exit(NULL);  
  152. }  

执行结果如下:

[cpp] view plaincopy
  1. fs@ubuntu:~/qiang/pthread$ ./cust_prod   
  2.   
  3. producer have delayed 2 seconds  
  4. producer writes 5 bytes to the FIFO  
  5. Now,the buffer left 2 spaces!  
  6.   
  7. Customer have delayed 2 seconds  
  8. customer reads 5 bytes from the FIFO  
  9.   
  10. producer have delayed 2 seconds  
  11. producer writes 5 bytes to the FIFO  
  12. Now,the buffer left 2 spaces!  
  13.   
  14. Customer have delayed 2 seconds  
  15. customer reads 5 bytes from the FIFO  
  16.   
  17. producer have delayed 2 seconds  
  18. producer writes 5 bytes to the FIFO  
  19. Now,the buffer left 2 spaces!  
  20.   
  21. Customer have delayed 2 seconds  
  22. customer reads 5 bytes from the FIFO  
  23.   
  24. producer have delayed 1 seconds  
  25. producer writes 5 bytes to the FIFO  
  26. Now,the buffer left 2 spaces!  
  27.   
  28. Customer have delayed 2 seconds  
  29. customer reads 5 bytes from the FIFO  
  30.   
  31. producer have delayed 1 seconds  
  32. producer writes 5 bytes to the FIFO  
  33. Now,the buffer left 2 spaces!  
  34.   
  35. Customer have delayed 3 seconds  
  36. customer reads 5 bytes from the FIFO  
  37.   
  38. producer have delayed 3 seconds  
  39. producer writes 5 bytes to the FIFO  
  40. Now,the buffer left 2 spaces!  
  41.   
  42. producer have delayed 1 seconds  
  43. producer writes 5 bytes to the FIFO  
  44. Now,the buffer left 1 spaces!  
  45.   
  46. Customer have delayed 2 seconds  
  47. customer reads 5 bytes from the FIFO  
  48.   
  49. Customer have delayed 1 seconds  
  50. customer reads 5 bytes from the FIFO  
  51.   
  52. producer have delayed 3 seconds  
  53. producer writes 5 bytes to the FIFO  
  54. Now,the buffer left 2 spaces!  
  55.   
  56. Customer have delayed 1 seconds  
  57. customer reads 5 bytes from the FIFO  
  58.   
  59. producer have delayed 2 seconds  
  60. producer writes 5 bytes to the FIFO  
  61. Now,the buffer left 2 spaces!  
  62.   
  63. Customer have delayed 2 seconds  
  64. customer reads 5 bytes from the FIFO  
  65.   
  66. producer have delayed 1 seconds  
  67. producer writes 5 bytes to the FIFO  
  68. Now,the buffer left 2 spaces!  
  69.   
  70. Customer have delayed 2 seconds  
  71. customer reads 5 bytes from the FIFO  
  72.   
  73. producer have delayed 1 seconds  
  74. producer writes 5 bytes to the FIFO  
  75. Now,the buffer left 2 spaces!  
  76.   
  77. producer have delayed 1 seconds  
  78. producer writes 5 bytes to the FIFO  
  79. Now,the buffer left 1 spaces!  
  80.   
  81. Customer have delayed 2 seconds  
  82. customer reads 5 bytes from the FIFO  
  83.   
  84. producer have delayed 2 seconds  
  85. producer writes 5 bytes to the FIFO  
  86. Now,the buffer left 1 spaces!  
  87.   
  88. Customer have delayed 3 seconds  
  89. customer reads 5 bytes from the FIFO  
  90.   
  91. Customer have delayed 1 seconds  
  92. customer reads 5 bytes from the FIFO  
  93.   
  94. producer have delayed 3 seconds  
  95. producer writes 5 bytes to the FIFO  
  96. Now,the buffer left 2 spaces!  
  97.   
  98. producer have delayed 1 seconds  
  99. producer writes 5 bytes to the FIFO  
  100. Now,the buffer left 1 spaces!  
  101.   
  102. Customer have delayed 2 seconds  
  103. customer reads 5 bytes from the FIFO  
  104.   
  105. Customer have delayed 1 seconds  
  106. customer reads 5 bytes from the FIFO  
  107.   
  108. producer have delayed 3 seconds  
  109. producer writes 5 bytes to the FIFO  
  110. Now,the buffer left 2 spaces!  
  111.   
  112. Customer have delayed 2 seconds  
  113. customer reads 5 bytes from the FIFO  
  114.   
  115. producer have delayed 2 seconds  
  116. producer writes 5 bytes to the FIFO  
  117. Now,the buffer left 2 spaces!  
  118. fs@ubuntu:~/qiang/pthread$  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/402313.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux 文件服务---------- nfs Server

Linux 文件服务nfs &#xff08;Network file system&#xff09;#网络文件系统 ---> 远程文件调用samba #文件共享&#xff08;unix /linux /windows &#xff09; ,只能适用于局域网。ftp #远程文件存取.(跨网络&#xff0c; 跨平台&#xff0c; 文件存取)。 nfs Server r…

VC命令行编译参数介绍

From: http://blog.csdn.net/zhangxinrun/article/details/5797122 CL.exe是控制Microsoft C和C编译器与链接器的32位工具。编译器产生通用对象文件格式(COFF)对象(.obj)文件。链接器产生可执行文件(.exe)或动态链接库文件(DLL)。 注意&#xff0c;所有编译器选项都区分大小写。…

在linux 5上配置戴尔MD3220i

http://zh.community.dell.com/techcenter/storage/f/150/t/2773.aspx转载于:https://blog.51cto.com/xs2013/1298568

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

在前面&#xff0c;我们学习了传统的进程间通信方式——无名管道&#xff08;pipe&#xff09;、有名管道&#xff08;fifo&#xff09;和信号&#xff08;signal&#xff09;。 下面我们来学习 System V IPC 对象&#xff1a; 1、共享内存&#xff08;share memory&#xff0…

VC程序员常用工具篇

1. IDE&#xff1a;钟情于VC6.0&#xff0c;但是也感觉Visual Studio2008和2010的强大,可能迟早得转到VS高版本上来。在安装VC6.0的时候记得安装sp6补丁和msdn&#xff08;MSDN_1.5_精简安装版 &#xff09;2. 辅助&#xff1a; Visual Assist&#xff0c;喜欢它代码自动补全&a…

Hibernate的批量操作

批量插入 Hibernate强制开启了一级缓存&#xff0c;缓存空间是有限的&#xff0c;如果批量操作的SQL语句太多&#xff0c;就会运行失败&#xff08;内存溢出&#xff09;&#xff0c; 因此在批量操作的时候&#xff0c;每执行一批SQL语句&#xff0c;都需要刷新缓存&#xff0c…

.balignl 16,0xdeadbeef浅析

http://zqwt.012.blog.163.com/blog/static/12044684201031102956976/ 最近在分析u-boot的源代码&#xff0c;看到这一行&#xff1a; .balignl 16, 0xdeadbeef不知道为什么要这样写&#xff0c;0xdeadbeef&#xff0c;明显是个单词组&#xff0c;写在这里有何意义呢&am…

使用maven导入任意jar包

http://mvnrepository.com/ 我这里&#xff0c;因为是spark1.5.2版本。 保存&#xff0c;maven会自动下载jar包到本地仓库。 转载于:https://www.cnblogs.com/lchzls/p/6281764.html

Linux下静态IP地址的设置及TFTP服务的搭建

TFTP&#xff08;Trivial File Transfer Protocol,简单文件传输协议&#xff09;是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议&#xff0c;提供不复杂、开销不大的文件传输服务。TFTP承载在UDP上&#xff0c;提供不可靠的数据流传输服务&#xff0c;…

ASCII码表

From: http://www.96yx.com/tool/ASC2.htm ASCII码表 信息在计算机上是用二进制表示的&#xff0c;这种表示法让人理解就很困难。因此计算机上都配有输入和输出设备&#xff0c;这些设备的主要目的就是&#xff0c;以一种人类可阅读的形式将信息在这些设备上显示出来供人阅读理…

inotify

Linux 2.6内核中的文件系统变化通知机制 一、 引言 众所周知&#xff0c;Linux 桌面系统与 MAC 或 Windows 相比有许多不如人意的地方&#xff0c;为了改善这种状况&#xff0c;开源社区提出用户态需要内核提供一些机制&#xff0c;以便用户态能够及时地得知内核或底层硬件设备…

bzoj 3924 幻想乡战略游戏

题目大意&#xff1a; 有边权点权的树&#xff0c;动态修改点权 每次修改后求带权重心x (\(minimize\) \(S\sum_i val[i]*dist[x][i]\)) 分析&#xff1a; 从暴力找突破口&#xff1a; 对于边x,y&#xff0c;设长度为len&#xff0c;切断后x半边树权值和为\(w_1\)&#xff0c;y…

Linux 系统应用编程——网络编程(服务器模型)

在网络通信过程中&#xff0c;服务端通常需要处理多个客户端。由于多个客户端的请求可能会同时到来&#xff0c;服务器端可采用不同的方法来处理。总体上来说&#xff0c;服务器端可采用两种模型来实现&#xff1a;循环服务器模型和并发服务器模型。 循环服务器模型是指服务器端…

makefile中的patsubst, wildcard, notdir

From:http://blog.sina.com.cn/s/blog_60cbc1700100nuhz.html 1、wildcard : 扩展通配符 2、notdir &#xff1a; 去除路径 3、patsubst &#xff1a;替换通配符 例子&#xff1a; 建立一个测试目录&#xff0c;在测试目录下建立一个名为sub的子目录 $ mkdir test $ cd test $…

搭建实用深度学习环境(Ubuntu16.10+Theano0.8.2+Tensorflow0.11.0rc1+Keras1.1.0)

在动手安装之前&#xff0c;首先要确定硬件&#xff0c;系统&#xff0c;准备安装软件的版本&#xff0c;确定这些软硬件之间是否相互支持或兼容。本文安装的主要环境和软件如下&#xff1a; Ubuntu16.10CUDA8.0(cudnn5.1,CNMEM)Theano0.8.2Tensorflow0.11.0rc1Keras1.1.0 显卡…

Statspack安装心得

一&#xff0c;在win7下应该以管理员身份运行&#xff0c;sqlplusw 二&#xff0c;安装前要要执行如下代码&#xff0c;创建表空间 SQL> create tablespace perfstat 2datafile d:\oracle\oradata\eygle\perfstat.dbf 3size 500M 4extent management local; eygle为你的数据…

Linux 系统应用编程——网络编程(基础篇)

一、网络体系结构 1、OSI模型和TCP/IP 模型 网络体系结构指的是网络的分层结构以及每层使用的协议的集合。其中最著名的就是OSI协议参考模型&#xff0c;他是基于国际标准化组织&#xff08;OSI&#xff09;的建议发展起来的。它分为7个层次&#xff1a;应用层、表示层、会话层…

函数的定义与调用

1.理解函数 函数是一段代码块&#xff0c;它只定义一次&#xff0c;但可以被执行或调用任意次。函数可以有参数&#xff0c;实参&#xff08;argument&#xff09;和形参&#xff08;parameter&#xff09;&#xff0c;实参是在运行时的函数调用时传入的参数&#xff0c;形参是…

C++中函数的默认参数

使用方法&#xff1a; &#xff08;1&#xff09;在函数声明或定义时&#xff0c;直接对参数赋值&#xff0c;该参数就是默认参数。&#xff08;2&#xff09;在函数调用时&#xff0c;省略部分或全部参数&#xff0c;这时就会使用默认参数进行代替。注意事项&#xff1a; &…

Linux 系统应用编程——网络编程(socket编程)

二、网络编程基础 1、套接字概述 套接字就是网络编程的ID。网络通信&#xff0c;归根到底还是进程间的通信&#xff08;不同计算机上的进程间的通信&#xff09;。在网络中&#xff0c;每一个节点&#xff08;计算机或路由器&#xff09;都有一个网络地址&#xff0c;也就是IP地…