目录

一、生产者消费者问题描述

二、解决思路

三、问题求解:

四、源码

五、运行结果:


一、生产者消费者问题描述

生产者消费者(producer—customer)问题是一个非常著名的进程同步问题。它描述的是:生产者进程在生产“产品”,消费者进程则消费这些“产品”,在生产者进程和消费者进程之间存在一个缓冲池(生产者将生产的产品放入该缓冲池,消费者则消费该缓冲池中的产品)。所有生产者进程、消费者进程都是相互独立的(即以异步的方式运行),但他们之间同时必须保持同步(即不允许消费者进程到空缓冲区取产品,也不允许生产者进程向满缓冲区存入产品)。

二、解决思路

我们使用队列(先进先出表)Queue来表示上述具有n个缓冲区的缓冲池。每投入(取出)一个产品,缓存池中就相应的插入(删除)一个节点。由于该缓冲池是被组织成队列的形式,因此,队空队满的判断条件分别如下:

q->front == q->rear;    //队空
q->front == (q->rear+1)%SIZE;    //队满

此外,我们引入一个整型变量num,置其初值为0,当生产者(消费者)进程向缓冲池投入(取走)一个产品时,num对应的加一(减一)。

同时,由于缓冲区是共享的,因此需要对生产者、消费者使用缓冲区进行限制,以此达到同步的效果,即在生产者向缓冲区投入产品时,消费者不得使用缓冲池;消费者向缓冲区取出产品时同理。

三、问题求解

通过以上的分析,我们可以得到一个解决思路如下:

void producer()
{sem_wait();lockf();QueueFull();Enqueue();unlockf();sem_post();
}
void customer()
{sem_wait();lockf();QueueEmpty();Dequeue();unlockf();sem_post();
}

这段伪代码的思路已经十分明确了。

·生产者进程向缓冲区投入产品,则num加一;消费者进程向缓冲区取出产品,则num减一

·为避免生产者进程和消费者进程同时使用资源,我们采用上锁的方式来达到独占资源的目标

·为了避免两个进程之间相互干扰,我们利用信号量机制来实现进程间互斥和同步

但是,仔细思考就会发现,仅仅只是这样是远远不够的。我们还必须保证队满不入、队空不取。因此,在上述结构的基础上,我们加入条件判断机制。

四、源码

由于容器Queue的容量为10,因此我只运行生产者、消费者各十次,且出于简单设计的角度,该程序仅仅展示了单生产者-单消费者的情况。其他的情况,如果后面有空余时间,我会尝试一下的。

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>#define TRUE  1
#define FALSE 0
#define SIZE 11typedef int QueueData;   //定义一个整型变量QueueData,与为基本数据类型定义新的别名方法一样 typedef struct _queue   //队列结构体
{int data[SIZE];int front;     // 指向队头的下标int rear;      // 指向队尾的下标
}Queue;struct data             //信号量结构体
{sem_t count;Queue q;
};struct data sem;
pthread_mutex_t mutex;  //互斥变量使用特定的数据类型
int num = 0; int InitQueue (Queue *q)   // 队列初始化
{if (q == NULL){return FALSE;}q->front = 0;q->rear  = 0;return TRUE;
}int QueueEmpty (Queue *q)      //判断空队情况
{if (q == NULL){return FALSE;}return q->front == q->rear;
}int QueueFull (Queue *q)     //判断队满的情况
{if (q == NULL){return FALSE;}return q->front == (q->rear+1)%SIZE;
} int DeQueue (Queue *q, int x)   //出队函数
{if (q == NULL){return FALSE;}if (QueueEmpty(q)){return FALSE;}q->front = (q->front + 1) % SIZE;x = q->data[q->front];return TRUE;
}int EnQueue (Queue *q, int x)   //进队函数
{if (q == NULL){return FALSE;}    if (QueueFull(q)){return FALSE;}    q->rear = (q->rear+1) % SIZE;q->data[q->rear] = x;return TRUE;
}void *Producer()
{int i=0;while(i<10){i++;int time = rand() % 10 + 1;          //随机使程序睡眠0点几秒           usleep(time * 100000);sem_wait(&sem.count);                 //信号量的P操作(使信号量的值减一) pthread_mutex_lock(&mutex);           //互斥锁上锁if(!QueueFull(&sem.q))                 //若队未满 {num++;                                EnQueue (&sem.q, num);              //消息进队printf("生产了一条消息,count=%d\n", num); }                                      else printf("Full\n");                                       pthread_mutex_unlock(&mutex);         //互斥锁解锁sem_post(&sem.count);                  //信号量的V操作(使信号量的值加一) }printf("i(producer)=%d\n",i);
}void *Customer()
{int i=0;while(i<10){i++;int time = rand() % 10 + 1;   //随机使程序睡眠0点几秒usleep(time * 100000);sem_wait(&sem.count);           //信号量的P操作pthread_mutex_lock(&mutex);    //互斥锁上锁if(!QueueEmpty(&sem.q))            //若队未空 {num--;DeQueue (&sem.q, num);       //消息出队printf("消费了一条消息,count=%d\n",num);}else  printf("Empty\n");pthread_mutex_unlock(&mutex);  //互斥锁解锁sem_post(&sem.count);         //信号量的V操作}printf("i(customer)=%d\n",i);
}int main()
{srand((unsigned int)time(NULL));//信号量地址,信号量在线程间共享,信号量的初始值 sem_init(&sem.count, 0, 10);    //信号量初始化(做多容纳10条消息,容纳了10条生产者将不会生产消息)pthread_mutex_init(&mutex, NULL);  //互斥锁初始化InitQueue(&(sem.q));   //队列初始化pthread_t producid;pthread_t consumid;pthread_create(&producid, NULL, Producer, NULL);   //创建生产者线程pthread_create(&consumid, NULL, Customer, NULL);   //创建消费者线程pthread_join(consumid, NULL);    //线程等待,如果没有这一步,主程序会直接结束,导致线程也直接退出。sem_destroy(&sem.count);         //信号量的销毁 pthread_mutex_destroy(&mutex);   //互斥锁的销毁return 0;
}

五、运行结果:

仔细分析可以认为达成实验目的。

经典进程同步问题(一)——生产者消费者问题相关推荐

  1. 操作系统:经典进程同步问题 之 生产者-消费者问题、读者-写者问题、哲学家进餐问题

    在进程同步中,经典的同步问题有:生产者-消费者问题.读者-写者问题.哲学家进餐问题. 一.生产者与消费者问题: 问题描述:使用一个缓冲区来保存物品,只有缓冲区没有满,生产者才可以放入物品:只有缓冲区不 ...

  2. 操作系统 | OS 经典同步问题之生产者-消费者问题,哲学家进餐问题

    小目录 1. 生产者-消费者问题 2. 哲学家进餐问题 3. 吸烟者问题 1. 生产者-消费者问题 生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语 ...

  3. java 生产者消费者同步_经典线程同步问题(生产者消费者)--Java实现

    原创作品,转载请注明出自xelz's blog 生产者-消费者(producer-consumer)问题是一个著名的线程同步问题.它描述的是:有一群生产者线程在生产产品,并将这些产品提供给消费者线程去 ...

  4. 经典并发问题:生产者-消费者

    前置知识 此处以Java描述该问题,需要Java并发的知识,这里附上一些不错的教程: Java Multitasking Youtube上的一个教程,非常实战,能快速找到感觉. The Java™ T ...

  5. Linux下生产者消费者问题的C语言实现

    注:查看全文请关注作者,或点击前往:生产者-消费者问题的C语言实现 实验六 生产者-消费者问题实现 实验题目 要求 在Linux操作系统下用C实现经典同步问题:生产者-消费者,具体要求如下: (1) ...

  6. 经典进程同步问题——生产者消费者问题

    问题描述 "生产者-消费者"问题 (producer/consumer problem) 是最著名的进程同步问题. 该问题描述了共享固定大小缓冲区的两个线程--即所谓的" ...

  7. 2.3.6 操作系统之进程同步与互斥经典问题(生产者-消费者问题、多生产者-多消费者问题、吸烟者问题、读者-写者问题、哲学家进餐问题)

    文章目录 0.前言 1.生产者-消费者问题 (1)问题描述 (2)问题分析 (3)如何实现? (4)实现互斥的P操作一定要在实现同步的P操作之后 (5)知识回顾与重要考点 2.多生产者-多消费者问题 ...

  8. 操作系统 | PV操作七大经典问题 生产者消费者 读者写者 哲学家进餐 理发师理发睡觉 和尚打水 吸烟者 吃水果

    一.生产者消费者问题 生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案 ...

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

    "生产者--消费者"问题是Linux多线程编程中的经典问题,主要是利用信号量处理线程间的同步和互斥问题. "生产者--消费者"问题描述如下: 有一个有限缓冲区( ...

最新文章

  1. 2021年大数据ELK(十九):使用FileBeat采集Kafka日志到Elasticsearch
  2. Java中使用BigDecimal进行浮点数精确计算 超大整数 浮点数等计算,没有数位限制...
  3. python3 deque(双向队列)
  4. 电子设计竞赛电源题(1)-电源题简介
  5. 每日一言学做人,古之学问,博大精深
  6. 牛客-无形的博弈【结论题,快速幂】
  7. 不用图片而用css3实现一些阴影特效
  8. Oracle数据库脚本学习:建用户、删用户、建表、改表、删表
  9. MFC 教程【14_SOCKET类的设计和实现】
  10. Python.Algorithms(2nd)pdf
  11. git-scm.com下载文件特别慢怎么办,自己拿吧
  12. 英语语法回顾2——并列句
  13. 神经网络的反向传播算法中矩阵的求导方法(矩阵求导总结)
  14. 【备忘】李炎恢老师HTML5+CSS3教程与课件代码【共享完毕】下载
  15. markdown和marktop是啥关系?
  16. 输入一串字符,统计每个字符数,用字典输出。
  17. ibm jazz_Jazz源代码管理管理指南
  18. bim oracle,IBMS和BIM的融合之路
  19. 实现app直播商城源码,先从简单的直播系统开始
  20. 百度搜索引擎接口测试报告

热门文章

  1. Mybatis查询:结果集的顺序引起的数据缺失和重复的坑
  2. kettle遍历抽取某目录下Excel文件数据
  3. 安规电容,X电容,Y电容
  4. vc6.0(完整绿色版)(支持XP、Win7、Win8、Win10)
  5. VR虚拟现实场景制作公司
  6. 连续小波变换应用于密集模态参数识别
  7. FloTHERM10.0安装说明
  8. docker images处理
  9. bzoj AC100~~~
  10. Redis6入门数据类型持久化主从集群