经典进程同步问题(一)——生产者消费者问题
目录
一、生产者消费者问题描述
二、解决思路
三、问题求解:
四、源码
五、运行结果:
一、生产者消费者问题描述
生产者消费者(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;
}
五、运行结果:
仔细分析可以认为达成实验目的。
经典进程同步问题(一)——生产者消费者问题相关推荐
- 操作系统:经典进程同步问题 之 生产者-消费者问题、读者-写者问题、哲学家进餐问题
在进程同步中,经典的同步问题有:生产者-消费者问题.读者-写者问题.哲学家进餐问题. 一.生产者与消费者问题: 问题描述:使用一个缓冲区来保存物品,只有缓冲区没有满,生产者才可以放入物品:只有缓冲区不 ...
- 操作系统 | OS 经典同步问题之生产者-消费者问题,哲学家进餐问题
小目录 1. 生产者-消费者问题 2. 哲学家进餐问题 3. 吸烟者问题 1. 生产者-消费者问题 生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语 ...
- java 生产者消费者同步_经典线程同步问题(生产者消费者)--Java实现
原创作品,转载请注明出自xelz's blog 生产者-消费者(producer-consumer)问题是一个著名的线程同步问题.它描述的是:有一群生产者线程在生产产品,并将这些产品提供给消费者线程去 ...
- 经典并发问题:生产者-消费者
前置知识 此处以Java描述该问题,需要Java并发的知识,这里附上一些不错的教程: Java Multitasking Youtube上的一个教程,非常实战,能快速找到感觉. The Java™ T ...
- Linux下生产者消费者问题的C语言实现
注:查看全文请关注作者,或点击前往:生产者-消费者问题的C语言实现 实验六 生产者-消费者问题实现 实验题目 要求 在Linux操作系统下用C实现经典同步问题:生产者-消费者,具体要求如下: (1) ...
- 经典进程同步问题——生产者消费者问题
问题描述 "生产者-消费者"问题 (producer/consumer problem) 是最著名的进程同步问题. 该问题描述了共享固定大小缓冲区的两个线程--即所谓的" ...
- 2.3.6 操作系统之进程同步与互斥经典问题(生产者-消费者问题、多生产者-多消费者问题、吸烟者问题、读者-写者问题、哲学家进餐问题)
文章目录 0.前言 1.生产者-消费者问题 (1)问题描述 (2)问题分析 (3)如何实现? (4)实现互斥的P操作一定要在实现同步的P操作之后 (5)知识回顾与重要考点 2.多生产者-多消费者问题 ...
- 操作系统 | PV操作七大经典问题 生产者消费者 读者写者 哲学家进餐 理发师理发睡觉 和尚打水 吸烟者 吃水果
一.生产者消费者问题 生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案 ...
- Linux 系统应用编程——多线程经典问题(生产者-消费者)
"生产者--消费者"问题是Linux多线程编程中的经典问题,主要是利用信号量处理线程间的同步和互斥问题. "生产者--消费者"问题描述如下: 有一个有限缓冲区( ...
最新文章
- 2021年大数据ELK(十九):使用FileBeat采集Kafka日志到Elasticsearch
- Java中使用BigDecimal进行浮点数精确计算 超大整数 浮点数等计算,没有数位限制...
- python3 deque(双向队列)
- 电子设计竞赛电源题(1)-电源题简介
- 每日一言学做人,古之学问,博大精深
- 牛客-无形的博弈【结论题,快速幂】
- 不用图片而用css3实现一些阴影特效
- Oracle数据库脚本学习:建用户、删用户、建表、改表、删表
- MFC 教程【14_SOCKET类的设计和实现】
- Python.Algorithms(2nd)pdf
- git-scm.com下载文件特别慢怎么办,自己拿吧
- 英语语法回顾2——并列句
- 神经网络的反向传播算法中矩阵的求导方法(矩阵求导总结)
- 【备忘】李炎恢老师HTML5+CSS3教程与课件代码【共享完毕】下载
- markdown和marktop是啥关系?
- 输入一串字符,统计每个字符数,用字典输出。
- ibm jazz_Jazz源代码管理管理指南
- bim oracle,IBMS和BIM的融合之路
- 实现app直播商城源码,先从简单的直播系统开始
- 百度搜索引擎接口测试报告