消费者和生产者问题

生产者消费者共享缓冲区,生产者向缓冲区中放数据,消费者从缓冲取中取数据,当缓冲区中被放满时,生产者进程就必须进入挂起状态,直到消费者从缓冲中取走数据时,生产者才能继续向缓冲区中存放数据,同样当缓冲取中没有数据时,消费者进程就必须进入挂起休眠状态,直到生产者向缓冲区中放入数据时,消费者才能被唤醒继续从缓冲区中取走数据。
生产者消费者问题,也称有限缓冲问题,是一个多线程同步问题的经典案例。

分析:

  • 1、对于变量empty和full 是去控制缓冲区产品的数量,防止超出缓冲区的大小
    假如现在只生产产品,而不去消费产品,empty降为0,full会上涨到100,满足了while内的条件,会陷入死循环,反复打印 “ 缓冲区满”,
  • 2、还会去加入一个锁,防止一个线程运行的时间片到了,进入其他线程消费或者生产产品,而未记录,产生错误
  • 3、如果线程在该时间片复内完成,线程就结束了,如果未完成,系统会将该线程放入就绪队列,等待下制CPU再度调度运行它,而且是接着上次执行的状态接着执行,
  • 4、用goto 语句 去防止不断的刷新缓冲区空 或缓冲区满

多消费者和多生产者代码:

#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>#define N 100
#define true 1
#define producerNum 10
#define consumerNum 5
#define sleepTime 1//对于线程函数即使不需要参数,也不能写成void 要写成void * a ,在线程创建函数处写NULL
//
typedef int semaphore;
typedef int item;//
//该缓冲区类似于队列,in 和 out 分别代表位置,入队和出对
item buffer[N] = { 0 };
int in = 0;
int out = 0;
int proCount = 0;    //记录产品ID
//empty 和 full 去记录缓冲区内产品数量,
//使用极端例子,假设只生产不消费,empty不断减小,减为0 时 缓冲区满,停止写入数据semaphore mutex = 1,empty = N, full = 0, proCmutex = 1;//用锁防止线程运行到中途时间片到
void * producer(void * a)
{while(true){while(mutex <= 0);while(empty <= 0){printf("缓冲区已满!\n");}empty --;mutex--;proCount ++;buffer[in] = proCount;in = (in + 1) % N;printf("生产的产品ID %d,缓冲区位置 %d\n",proCount,in);mutex ++;full ++;sleep(1);}
}
void *consumer(void * b)
{while(true){while(mutex <= 0);while(full <= 0){printf("缓冲区为空\n");}full --;mutex --;int nextc = buffer[out];buffer[out] = 0;out = (out + 1) % N;printf("\t\t\t\t消费的产品ID %d,缓冲区位置为%d\n",nextc,out);mutex ++;empty ++;sleep(1);}
}
int main(void)
{pthread_t pthreadPool[producerNum + consumerNum];for(int i = 0;i< producerNum;i++){pthread_t temp;if(pthread_create(&temp,NULL,producer,NULL) == -1){printf("%d : create producer pthread failed\n",__LINE__);exit(1);}pthreadPool[i] = temp;}for(int i = 0;i < consumerNum;i++ ){pthread_t temp;if(pthread_create(&temp,NULL,consumer,NULL) == -1){printf("%d : create consumer pthread failed\n",__LINE__);exit(2);}}void *result;//使用pthread_join结束线程是因为线程运行会产生碎片垃圾,系统无法自动回收for(int i = 0;i < producerNum + consumerNum ;i++){if(pthread_join(pthreadPool[i],&result) == -1){printf("failed to recollect\n");exit(3);}}return 0;}

单消费者和单生产者代码:

和多消费者多生产者代码基本一致,在创建线程时不同

#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<semaphore.h>//如果线程在该时间片复内完成,线程就结束了,如果未完成,系统会将该线程放入就绪队列,等待下制CPU再度调度运行它,而且是接着上次执行的状态接着执行,
//用goto 语句 去防止不断的刷新缓冲区空 或缓冲区满typedef  int semaphore;typedef int item;#define true 1
#define N 3
#define sleepTime 1item buffer[N] = { 0 };
int in = 0;
int out = 0;
int proCount = 1;semaphore mutex = 1,empty = N, full = 0,proCmutex = 1;
void * producer(void * a)
{while(true){while(empty <= 0){printf("缓冲区已满!\n");goto a;}empty --;while(mutex <= 0); mutex --;proCount ++;buffer[in] = proCount;in = (in + 1) % N;printf("生产的产品ID %d,缓冲区位置 %d\n",proCount,in);mutex++;full ++;a:sleep(2);}
}
void * consumer(void * b)
{while(true){while(mutex <= 0);while(full <= 0){printf("缓冲区为空!\n");goto a;}full --;mutex --;int nextc = buffer[out];buffer[out] = 0;out = (out + 1) % N;printf("\t\t\t\t消费的产品ID %d,缓冲区位置为%d\n",nextc,out);mutex++;empty ++;a:sleep(sleepTime);}
}int main(void)
{pthread_t proID,conID;if(pthread_create(&proID,NULL,producer,NULL) == -1){printf("%d : create producer pthread failed \n",__LINE__);exit(1);}if(pthread_create(&conID,NULL,consumer,NULL) == -1){printf("%d : create consumer pthread failed\n",__LINE__);exit(2);}void * result;if(pthread_join(proID,&result) == -1){printf("%d : recollect producer failed\n",__LINE__);exit(3);}if(pthread_join(conID,&result) == -1){printf("%d : recollect consumer failed\n",__LINE__);exit(4);}return 0;
}

哲学家问题

有五个哲学家绕着圆桌坐,每个哲学家面前有一盘面,两人之间有一支筷子,这样每个哲学家左右各有一支筷子。哲学家有2个状态,思考或者拿起筷子吃饭。如果哲学家拿到一只筷子,不能吃饭,直到拿到2只才能吃饭,并且一次只能拿起身边的一支筷子。一旦拿起便不会放下筷子直到把饭吃完,此时才把这双筷子放回原处。如果,很不幸地,每个哲学家拿起他或她左边的筷子,那么就没有人可以吃到饭了。
哲学家进餐问题是一个多线程运用的经典例子,涉及到线程同步/互斥,临界区访问问题以及死锁问题。

分析:

  • 1、原子操作: 指的是有多部操作组成的一个操作。如果该操作不能原子的进行,则要么执行完所有步骤,要么一步也不执行,不可能只执行所有步骤的一个子集
  • 2、现代操作系统中,一般都提供了原子操作来实现一些同步操作,所谓原子操作,也就是一个独立而不可分割的操作,在单核环境中,一般意义下原子操作中线程不会被切换,线程切换要么在原子操作之前,要么在原子操作之后。更广泛的意义下原子操作是指一系列必须整体完成的操作步骤,如果任何一步操作没有完成,那么所有完成的步骤,都必须回滚,这样就可以保证要么所有操作步骤都未完成,要么所有操作步骤都被完成
  • 3、该问题用了一条汇编指令执行了交换函数,防止交换失败
void xchg(int *x,int *y)
{__asm__("xchgl %0,%1":"=r" (*x) : "m" (*y));
}
  • 4、加入一把全局锁,是为了能让某一个线程得到想要的资源,尽可能满足这一个线程,但是一定要注意解锁位置
  • 5、p、v操作
sem_init(&r,0,4)
设置信号量的初始值为4,保证最多有4个线程并行,第5个线程会阻塞
p操作                                     v操作
s = s - 1                                 s = s + 1;
if(s >= 0)                                if(s > 0)线程继续执行                                线程继续执行
if(s < 0)                                 if(s <= 0)线程阻塞                                    该线程去唤醒另一个在该信号量上等待的线程,然后继续执行
  • 6、各方式原因见:哲学家问题

代码:

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<time.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>#define N 5
#define sleepTime 2
//信号量使用的参数
pthread_mutex_t chopsticks [N];
pthread_mutex_t mutex;
sem_t r;
int philosophers[N] = { 0,1,2,3,4 };
//swap指令需要的参数
int islocked[N] = { 0 };
//互斥量使用的参数
pthread_mutex_t chops[N];//交换函数 ,汇编指令void xchg(int *x,int *y)
{__asm__("xchgl %0,%1":"=r" (*x) : "m" (*y));
}//这个函数使用的解决方法是最多容许四个哲学家拿起左筷子void philosopher(void * arg)
{int i = *(int *)arg;int left = i;int right = (i + 1) % N;int leftkey;int rightkey;while(1){leftkey = 1;rightkey = 1;printf("哲学家 %d正在思考问题\n",i);sleep(sleepTime);printf("哲学家 %d饿了\n",i);sem_wait(&r);//56-60行   如果想要的筷子被占用,让该线程挂起,陷入死循环do{xchg(&leftkey,&islocked[left]);}while(leftkey);//筷子属于共享资源,不能同时被拿起,要加锁pthread_mutex_lock(&chopsticks[left]);printf("哲学家%d拿起了 %d号筷子,现在只有一支筷子,不能进餐\n",i,left);do{xchg(&rightkey,&islocked[right]);}while(rightkey);pthread_mutex_unlock(&chopsticks[right]);printf("哲学家%d拿起了 %d号筷子,现在有两只筷子,开始进餐\n",i,right);sleep(sleepTime);islocked[left] = 0;printf("哲学家%d放下了 %d号筷子\n",i,left);pthread_mutex_unlock(&chopsticks [left]);islocked[right] = 0;printf("哲学家%d放下了 %d号筷子\n",i,right);pthread_mutex_unlock(&chopsticks[right]);sem_post(&r);}
}
void philosopher2(void *arg)
{int i = *(int *)arg;int left = i;int right = ( i + 1 ) % N;while(1){printf("哲学家%d 正在思考问题\n",i);sleep(sleepTime);printf("哲学家%d 饿了\n",i);if(i % 2 == 0 )   //偶数哲学家,先右后左{pthread_mutex_lock(&chopsticks [right]);printf("哲学家%d拿起了%d号筷子,现在有一支筷子,不能进餐\n",i,right);pthread_mutex_lock(&chopsticks[left]);printf("哲学家%d拿起了%d号筷子,现在有两支筷子,开始进餐\n",i,left);sleep(sleepTime);pthread_mutex_unlock(&chopsticks [right]);printf("哲学家%d放下了%d号筷子\n",i,right);pthread_mutex_unlock(&chopsticks [left]);printf("哲学家%d放下%d号筷子\n",i,left);}else    //奇数哲学家,先右后左{pthread_mutex_lock(&chopsticks[left]);printf("哲学家%d拿起了%d号筷子,现在有一支筷子,不能进餐\n",i,left);pthread_mutex_lock(&chopsticks[right]);printf("哲学家%d拿起了%d号筷子,现在有两支筷子,开始进餐\n",i,right);sleep(sleepTime);pthread_mutex_unlock(&chopsticks[right]);printf("哲学家%d放下了%d号筷子\n",i,right);pthread_mutex_unlock(&chopsticks [left]);printf("哲学家%d放下了%d号筷子\n",i,left);}}}
//加入一把全局锁,是为了能让某一个线程得到想要的资源,尽可能满足这一个线程
//注意解锁位置
void philosopher3(void * arg)
{int i = *(int *)arg;int left = i;int right = (i + 1) % N;while(1){printf("哲学家%d正在思考问题\n",i);sleep(sleepTime);printf("哲学家%d饿了\n",i);pthread_mutex_lock(&mutex);pthread_mutex_lock(&chopsticks[left]);printf("哲学家%d拿起了%d号筷子,现在只有一支筷子,不能进餐\n",i,left);pthread_mutex_lock(&chopsticks[right]);printf("哲学家%d拿起了%d号筷子,现在有两支筷子,开始进餐\n",i,right);pthread_mutex_unlock(&mutex);sleep(sleepTime);pthread_mutex_unlock(&chopsticks[left]);printf("哲学家%d放下了%d号筷子\n",i,left);pthread_mutex_unlock(&chopsticks[right]);printf("哲学家%d放下了%d号筷子\n",i,right);}
}
int main(void)
{pthread_t PHD[N];pthread_mutex_init(&mutex,NULL);sem_init(&r,0,4);for(int i = 0;i<N;i++){pthread_mutex_init(&chopsticks[i],NULL);}for(int i = 0; i< N ;i++){pthread_create(&PHD[i],NULL,(void *)philosopher3,&philosophers[i]);}for(int i = 0 ;i < N;i++){pthread_join(PHD[i],NULL);}sem_destroy(&r);for(int i = 0;i < N;i++){pthread_mutex_destroy(&chopsticks[i]);}pthread_mutex_destroy(&mutex);
}

消费者生产者问题,哲学家问题相关推荐

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

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

  2. 1_RabbitMQ初入门入门Hello消费者+生产者

    文章目录 1_RabbitMQ初入门 1.RabbitMQ的介绍 1.工作原理&发送/接收消息的流程 2. 为什么要使用消息队列? 3.使用了消息队列有什么缺点? 2.安装RabbitMQ 3 ...

  3. 【SEUSE】操作系统实验:消费者-生产者问题

    操作系统实验:消费者-生产者问题 README 一.实验目的 二.实验内容 三.实验步骤 四.主要数据结构及其说明 五.程序运行时的初值和运行结果 六.实验体会 七.源程序 README 本实验报告仅 ...

  4. 操作系统(四) | 经典进程的同步问题(生产者--消费者问题、哲学家进餐问题、读者--写者问题)

    文章目录 生产者--消费者问题 分析 实现 哲学家进餐问题 方法一:最多4人同时拿左筷子,最终保证一人能进餐 方法二:同时给左右筷子 解法1:AND信号量 解法2:信号量保护机制 方法三:让奇数先左后 ...

  5. kafka消费者如何读同一生产者消息_Kafka消费者生产者实例

    为了更为直观展示Kafka的消息生产消费的过程,我会从基于Console和基于Application两个方面介绍使用实例.Kafka是一个分布式流处理平台,具体来说有三层含义: 它允许发布和订阅记录流 ...

  6. java多线程之消费者生产者模式

    /*@author shijin * 生产者与消费者模型中,要保证以下几点: * 1 同一时间内只能有一个生产者生产     生产方法加锁sychronized * 2 同一时间内只能有一个消费者消费 ...

  7. 在Linux系统下生产者消费者,生产者-消费者问题实现 (linux下C语言)

    操作系统的一个经典问题是"生产者-消费者"问题, 这涉及同步信号量和互斥信号量的应用, 在这里,我用线程的同步和互斥来实现. /* * author 张文 * 2008/06/20 ...

  8. 多线程锁,线程池,消费者生产者模型

    锁是怎么存在的? 在python建立之初,开发者目的是为了快速把语言开发出来,如果加上GIL(c语言加锁),切换时按照100条字节指令来进行线程间的切换 为什么加锁? 非线程安全,控制一段代码 1.l ...

  9. java多线程队列_java多线程消费者生产者模式(BlockingQueue 通过阻塞队列实现)

    import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; /** * Cr ...

  10. java消费者生产者设计模式_java 多线程并发设计模式之四: 生产者消费者模式

    生产者消费者模式是一个经典的多线程设计模式,其核心思想是:有两类线程和一个内存缓冲区或者队列, 一类线程发起任务,并提交到队列中.另一类线程用来处理这些任务,叫做消费者线程. 这两类线程进行通信的桥梁 ...

最新文章

  1. ACM入门之【离散化】
  2. html中map属性怎么用的,HTML IMAGE MAP标签的使用
  3. 教你 4 步搭建弹性可扩展的 WebAPI
  4. 路径总和 II—leetcode113
  5. e5 2630v4 php性能,至强E5 V4性能表现测试
  6. java多线程(二)——锁机制synchronized(同步方法)
  7. bzoj 3261 最大异或和【可持久化trie】
  8. 花花省淘宝客APP源码带淘宝京东拼多多唯品会优惠券自营商城本地生活CPS外卖优惠电影票话费
  9. Volatility3 windows插件详解
  10. 2019最新个税计算_python
  11. 国美易卡利用数据挖掘技术,国美易卡精准分析决策
  12. python 乌龟绘图turtle模块的使用
  13. 【Xilinx】Zynq\MPSoc\Versal不同速度等级下的ARM主频
  14. 最热网友收藏:深入理解C语言指针的奥秘((2007年第3周)
  15. Django 教程之数据库模型
  16. android 第三方扇形图,Android扇形图(饼状图)
  17. 什么是SVN(Subversion)?为什么要用SVN?
  18. html如何实现加载动画
  19. 给中国学生的第五封信
  20. 机器学习中常说的CV是什么?

热门文章

  1. “虚度”一下时光,给老友写封信
  2. 思科1242 AP无法连接到无线控制器
  3. 网易云音乐java爬虫_Java爬取网易云音乐民谣并导入Excel分析
  4. (一)VirtualBox安装增强功能
  5. python微信投票该用户被锁定、恢复时间_微信登录多久恢复正常
  6. java 200以内的素数_Java——200以内的质数
  7. 【2015-2016,我在路上】
  8. 找出若干个非零数中的最小值以及它们的平均值
  9. 嵇少峰:互联网金融草根时代终结
  10. 1次阿里面试经验,4天走完全部流程,看这里对你有帮助!