生产者消费者问题(Producer-consumer problem)

2023-05-16

概述

生产者消费者问题,也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。其中生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。

问题分析

1.要保证不让生产者在缓存还是满的时候仍然要向内写数据;
2.不让消费者试图从空的缓存中取出数据。
生产者和消费者对缓冲区互斥访问是互斥关系,同时生产者和消费者又是一个相互协作的关系,只有生
产者生产之后,消费者才能消费,他们也是同步关系。

只有生产者和消费者两个进程,正好是这两个进程存在着互斥关系和同步关系。那么需要解决的是互斥
和同步PV操作的位置。我们使用了三个信号量:full 和 empty用来解决唤醒的问题 ,而信号量mutex作为互斥信号量,它用于控制互斥访问缓冲池,互斥信号量初值为 1;信号量 full 用于记录当前缓冲池中“满”缓冲区数,初值为0。信号量 empty 用于记录当前缓冲池中“空”缓冲区数,初值为n。新的数据添加到缓存中后,full 在增加,而 empty 则减少。如果生产者试图在 empty 为0时减少其值,生产者就会被阻塞。下一轮中有数据被消费掉时,
empty就会增加,生产者就会被“唤醒”。

mypro.c

/*************************************************************************
	> File Name: mypro.c
	> Author: Xianghao Jia
	> mail: xianghaojia@sina.com
	> Created Time: Mon 18 Nov 2019 07:03:41 PM PST
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "queue.h"

#define CONSUMER_COUNT

sem_t vacancy;//空位
sem_t goods;//物品数量
sem_t sem_mutex;//互斥信号量

int main(int argc, char ** argv)
{
	pthread_t consumer_id[3];
	pthread_t productor_id;
	// 创建队列
	QUEUE * queue = queue_init();
	if(queue == NULL)
	{
		return -1;
	}
	// 初始化信号量
	sem_init(&vacancy, 0, 10);
	sem_init(&good, 0, 0);
	sem_init(&sem_mutex ,0 , 1);

	int i = 0;
	// 创建3个消费者
	for(i = 0; i < CONSUMER_COUNT; i++)
	{
		if(0 == pthread_create(&consumer_id[i], NULL, consumer_routine, queue_head))
		{
			perror("pthread_create");
			exit(1);
		}
	}
	// 创建生产者
	if(0 == pthread_create(&consumer_id[i], NULL, productor_routine, queue_head))
	{
		perror("pthread_create");
		exit(1);
	}
	// 用来停止程序
	getchar();

	// 取消线程
	for(i = 0; i < CONSUMER_COUNT; i++)
	{
		pthread_cancel(consumer_id[i]);
	}
	// 接合线程
	pthread_join(productor_id, NULL);
	for(i = 0; i < CONSUMER_COUNT; i++)
	{
		pthread_join(consumer_id[i], NULL);
	}
	
	// 销毁信号量
	sem_destroy(&vacancy);
	sem_destroy(&goods);
	sem_destroy(&sem_mutex);
	// 销毁队列
	queue_destroy(queue);

	return 0;
}


void *consumer_routine(void *arg)
{	
	printf("thread consumer start...\n");
	QUEUE * queue = (QUEUE *)arg;

	while(1)
	{
		sem_wait(&goods);
		sem_wait(&sem_mutex);
		
		if(exit_flag == 1)
		{
			printf("thread consumer is exiting\n");
			break;
		}
		// 获得队列首
		printf("consume %d\n",queue_front(queue));
		// 弹出队首
		queue_out(queue);
	
		sem_post(&sem_mutex);
		sem_post(&vacancy);
		usleep(random() % 10000);
	}
	pthread_exit(NULL);
}

void *productor_routine(void *arg)
{
	printf("thread productor start...\n");
	QUEUE * queue = (QUEUE *)arg;

	while(1)
	{
		sem_wait(&vacancy);
		sem_wait(&sem_mutex);
		
		if(exit_flag == 1)
		{
			printf("thread productor is exiting\n");
			break;
		}
		// 创建节点到队列中
		int n = random() % 100;
		queue_in(queue, n);
		printf("product %d\n", n);

		sem_post(&sem_mutex);
		sem_post(&goods);
		usleep(random() % 10000);
	}
	pthread_exit(NULL);	
}

queue.h

#ifndef _QUEUE_H
#define _QUEUE_H
#define QUEUE_DEEP 10

extern int myerror;

typedef struct Node
{
	//	BINODE *pnode;
	int num;
	int count;
	struct Node *next;
}QNODE, QUEUE;

int queue_is_empty(QNODE *queue);
void queue_destroy(QNODE *queue);
int queue_out(QNODE *queue);
int queue_in(QNODE *queue, int n);
int queue_front(QNODE *queue);
int queue_is_full(QNODE *queue);
QNODE *queue_init();
#endif

queue.c

#include "queue.h"
#include <stdio.h>

int myerror = 0;

QNODE *queue_init()
{
	QNODE *head = malloc(sizeof(QNODE));
	if (head == NULL)
	{
		return NULL;
	}
	memset(head, sizeof(QNODE));
	return head;
}

int queue_is_empty(QNODE *queue)
{
	return queue->next == NULL;
}
void queue_destroy(QNODE *queue)
{
	while (queue != NULL)
	{
		QNODE *temp = queue->next;
		free(queue);
		queue = temp;
	}
}
/*
	取出队列首段的元素
*/
int queue_out(QNODE *queue)
{
	if (queue->next == NULL)
	{
		return -1;
	}
	QNODE * temp = queue->next;
	queue->next = temp->next;
	free(temp);
	return 0;
}
/*
	将元素添加到队尾
*/
int queue_in(QNODE *queue, int n)
{
	while (queue->next)
	{
		queue = queue->next;
	}
	QNODE * temp = malloc(sizeof(QNODE));
	if (temp == NULL)
	{
		return -1;
	}
	temp->next = NULL;
	temp->num = n;
	queue->next = temp;
	return 0;
}
int queue_front(QNODE *queue)
{
	if (queue->next == NULL)
	{
		myerror = 1;
		return -1;
	}
	return queue->next->num;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

生产者消费者问题(Producer-consumer problem) 的相关文章

  • PIXHawk用QGC刷Firmware

    1 准备版本 2 开始刷 确定后会出现弹窗 xff0c 再弹窗的文件名处粘贴
  • Xfce4快捷键个性化配置(个人向)

    将xfce4部分常用快捷键设置为Gnome下的快捷键 窗口操作 xff08 在 窗口管理器 gt 键盘 里 xff09 切换同一应用的窗口 xff1a Alt 43 96 最大化窗口 xff1a Super 43 上隐藏窗口 xff1a S
  • 树莓派安装Dronekit连接PIX读取基础数据

    本文主要参考于苍穹四轴DIY的公众号文章 xff1a http span class token operator span span class token operator span span class token operator
  • PX4调试起飞

    一 下载固件 在px4的git上找到相应对于硬件型号的固件 xff1b 二 烧录固件 在qgc上 xff0c 点击高级上的自定义 xff0c 即可烧录相应固件 xff1b 三 选择机架 校准传感器 设置遥控器 选择机架类型之后 xff0c
  • PX4编译——搭建你的第一个应用(Hello Shy)

    一 编译环境 1 ubuntu20 04 2 px4 V2 二 编写测试程序 下载好px4code之后 xff0c 在src examples px4 simple app里面有cmakelist txt和px4 sample app cp
  • PX4开发说明

    本栏文档主要参考PX4的用户指导 xff1b 记录在px4开发过程中的心得体会和备忘 xff1b PX4 User Guide https docs px4 io master en dev setup dev env html
  • prometheus学习

    记录一下在阿木实验室 学习开源项目prometheus的过程
  • Error: No valid host was found.

    使用openstack创建虚拟机经常会遇到以下的这个错误 Error No valid host was found There are not enough hosts available 从字面意思就可以看出是无法找到可用的host的资
  • debian sid 安装 sopcast

    刚刚装了sopcast 由于是编译的 xff0c 所以记录一下以便以后删除干净 http sopcast com download linux html 上有详细说明 1 xff09 下载 sp auth tgz xff0c 把sp sc
  • 2.1 mavros发布位置指令控制px4

    1 说明 写一个节点给px4发送位置控制指令 xff0c 比如我想让飞机飞到10 xff0c 10 xff0c 10这个坐标 xff1b 2 发布和订阅的mavros主题 发布的主题 xff1a mavros setpoint positi
  • 2.2 mavros发布姿指令控制PX4

    说明 使用遥控飞行 px4在stablize模式下 xff0c 我们使用遥控器去控制px4飞行 xff1b 在飞行过程中 xff0c 通常我们用4个通道就可以控制飞机飞行 xff1b 其中roll pitch yaw打杆的量就是我们期望无人
  • 关于PX4上PID调参

    使用PX4 log view 工具 地址 setp response for roll rate 找到setp response for roll rate这个图片 从图片中可以看到 xff0c roll方向的角速度响应时间不够快 xff1
  • 【record】1、Prometheus-V2 初体验

    一 环境搭建 平时习惯使用虚拟机 xff0c 刚好阿木的公众号里面有送镜像 xff0c 于是在V1的时候就用这个镜像在run了 xff0c 这次V2出来 xff0c 直接pull就可以开始起飞了 xff1b xff08 感觉用虚拟机加镜像是
  • 【record】2、使用非官方遥控器适配prometheus的驱动修改

    0 前言 xff1a prometheus V2推荐使用阿木的遥控器 但是家里遥控器实在太多了 xff0c 所以就尝试修改一下prometheus里关于joystick的驱动 xff0c 使其适配prometheus的控制 xff1b 本篇
  • 【recode】3、地面站使用步骤与体验

    一 前言 从Prometheus的V1到V2 xff0c 无人机的状态显示是在终端中 xff0c 在一堆字符中寻找想要关注的信息 xff0c 确实硬核 xff1b 而今 xff0c 随着社会与科技的发展 xff0c Prometheus也开
  • 【recode】4、二维码自主降落与重复测试code修改

    0 前言 使用二维码辅助无人机降落 xff0c 模拟飞机先飞到二维码上空一定的高度 xff0c 然后切换到command control模式 xff1b 飞机会自动识别二维码的位置然后调整自身的X和Y位置信息 xff0c 同时控制高度进行下
  • 【code review】2、关于高度的估计过程

    0 前言 在定高模式中 xff0c 飞控需要有当前高度的信息 xff0c 也就是z的position信息 xff0c 进行Z轴的位置环控制 xff1b 那么这个Z轴的位置信息是怎么来的呢 xff1f 本文为在解读wukong FPV源码中Z
  • (开源)正点原子飞控+北醒tof+优象光流——室内定点(一)

    1 说明 xff1a 前几篇文章讲述了如何使用tof的数据实现飞机的定高 xff1b 接下来分享的是如何使用光流来定点 xff1b 主要分为以下几个步骤 xff1a 1 xff09 添加光流驱动 xff0c 获得x y轴方向的观测速度 xf
  • STM32的三种更新固件的方式

    说明 xff1a stm32有三种更新固件的方式 xff0c 分别为 xff08 1 xff09 DFU模式 xff08 Development Firmware Upgrade 即 开发固件升级 xff09 xff1b xff08 2 x
  • 有哪些比较好用的安卓模拟器(电脑端)

    模拟器帮助我们实现在电脑上玩手游的下载 目前市面上安卓模拟器软件看着种类繁多 xff0c 哪些模拟器比较好用呢 xff1f 但其实只有两大技术流派 xff1a Bluestacks和Virutalbox Bluestacks的历史可以追溯到

随机推荐

  • [icm42688]_readme

    记录一个使用icm42688的坑 xff1b 上图为42688的引脚连接图 xff1b 引脚说明处标注如果FSYNC不使用需要接地 xff1b 在实际测试驱动的过程中 xff0c 由于没有将该pin接地 xff0c 所以无法读取id 从机没
  • atbetaflight——指定commit号编译固件

    一 说明 在开发过程中 xff0c 比如成员A上传了一次code 而成员B需要测试本次提交的code xff0c 但是由于没有搭建ci 成员B就需要自己拉code编译 xff0c 本文将详细说明编译步骤 xff1b 二 步骤 1 使用vsc
  • atbf中imu数据的读取与处理方式

    一 说明 本文为作者在阅读atbf源码的过程中 xff0c 对atbf中imu数据的读取和处理方式的个人理解 xff0c 可能存在不对之处 xff0c 意在抛砖引玉 xff0c 请各位老师多多指正 xff1b 二 数据读取流程图 1 tar
  • atbf中imu数据读取逻辑分析仪抓取

    一 说明 使用逻辑分析仪抓区imu的spi和中断io的信号 xff0c 从而侧面描述atbf在imu上的数据读取方式 xff1b 二 硬件说明 1 硬件材料 1 mcu at32F437开发板 2 imu icm42688p 3 逻辑分析仪
  • cmake-自动识别新增子模块

    实际的项目中可能会有这种需求 xff0c 随着项目的进行 xff0c 会有新增的子模块 xff0c 如果每新增一个子模块 xff0c 顶层CMakeLists txt都要同步修改一次 xff0c 一般工程代码加入了版本控制 xff0c 那么
  • CSDN每日一练c++难题-大数加法 C语言

    题目名称 xff1a c 43 43 难题 大数加法 时间限制 xff1a 1000ms内存限制 xff1a 256M 题目描述 大数一直是一个c语言的一个难题 现在我们需要你手动模拟出大数加法过程 请你给出两个大整数加法结果 输入描述 x
  • Ubuntu软件包资源官网下载教程(包含所有下载源)

    官网地址 国外 xff1a Ubuntu Ubuntu Packages Search https packages ubuntu com 国内 xff1a Ubuntu Ubuntu Packages Search https packa
  • 基于ROS的YOLOV3实现目标检测项目过程记录

    lt link rel 61 34 stylesheet 34 href 61 34 https csdnimg cn release blogv2 dist mdeditor css editerView ck htmledit view
  • darknet_ros(yolo移植到ros系统)代码分析

    lt link rel 61 34 stylesheet 34 href 61 34 https csdnimg cn release blogv2 dist mdeditor css editerView ck htmledit view
  • DSP28335的PWM信号

    DSP的PWM信号 简介 DSP28335共12路16位的ePWM xff0c 能进行频率和占空比控制 ePWM的时钟TBCLK 61 SYSCLKOUT HSPCLKDIV CLKDIV PWM信号频率由时基周期寄存器TBPDR和时基计数
  • Kubernetes (k8s)最佳安全实践指南

    对于大部分 Kubernetes 用户来说 xff0c 安全是无关紧要的 xff0c 或者说没那么紧要 xff0c 就算考虑到了 xff0c 也只是敷衍一下 xff0c 草草了事 实际上 Kubernetes 提供了非常多的选项可以大大提高
  • DSP28335 CAN模块详解

    1 CAN2 0B协议简述 TMS320F28335上有2个增强型CAN总线控制器 xff0c 符合CAN2 0B协议 xff0c 其总线波特率可达到1Mbps 符合CAN2 0B协议的数据帧为扩展数据帧 xff0c 即采用29位标识符 数
  • DSP28335看门狗复位

    1 看门狗时钟 看门狗时钟发生器 WDCLK 61 CLKOUT 512 xff0c 当HALT时停止 6 bits预定标WDPS选择 xff1a 将WDCLK再分频后送给看门狗定时器 WDPS为WDCR的2 0 位 其6 bits配置作用
  • DSP28335 看门狗初始化函数

    DSP28335 看门狗初始化函数 看门狗初始化程序 入口参数为系统定时复位时间 在需要复位看门狗计数器的地方调用程序ServiceDog 此程序在文件DSP2833x SysCtrl c中 详细说明在 TMS320x
  • Keil5编译error:core_cm3.h

    当打开现成的工程项目时 xff0c 编译出现一堆错误 xff0c 大部分错误出现关于 core cm3 h 这个文件 xff0c 那么大概率可能跟Keil5的版本有关 xff0c 如下 xff1a 可能原因 xff1a 打开魔术棒 gt T
  • Simulink创建子系统,创建引用模型,调用模型,加密模型

    Simulink创建子系统 创建引用模型 调用模型 加密模型 一 创建子系统 1 创建新工程 并添加Logical Operator Unit Delay连线 完成如下图 全选所有模块 右键选择 基于所选内容创建子系统 ctrl G 完成如
  • 自动驾驶 2D 单目\双目\多目视觉方法 一(Pseudo-LiDAR,Mono3D,FCOS3D,PSMNet)

    文章目录 概述单目3D感知3D目标检测单目深度估计 双目3D感知双目3D目标检测双目深度估计 Pseudo LiDAR1 核心思路总结2 要点分析 Mono3DFCOS3DPSMNet 概述 自动驾驶中必不可少的3D场景感知 因为深度信息
  • [C语言] 利用库函数实现查找指定键值对功能

    1 功能描述 键值对 xff08 key 61 value xff09 字符串 xff0c 在开发中经常使用 要求1 xff1a 请自己定义一个接口 xff0c 实现根据key获取 要求2 xff1a 编写测试用例 要求3 xff1a 键值
  • 【C++】Clang-Format:代码自动格式化(看这一篇就够了)

    文章目录 Clang format格式化C代码1 引言 amp 安装1 1引言1 2 安装 2 配置字解释2 1 language 编程语言2 2 BaseOnStyle 基础风格2 3 AccessModifierOffset 访问性修饰
  • 生产者消费者问题(Producer-consumer problem)

    概述 生产者消费者问题 xff0c 也称有限缓冲问题 xff08 英语 xff1a Bounded buffer problem xff09 xff0c 是一个多线程同步问题的经典案例 该问题描述了两个共享固定大小缓冲区的线程 即所谓的 生