生产者消费者问题——C++ windows版 多生产者多消费者的队列实现

  最进要写一个多线程加载资源的资源管理器(ResourceManager)和多线程音频解码器(MultiThread
Decoder)。因为距最近一次用到多线程放下好久了,所以今天把生产者消费者问题练一下手。

  为什么选择生产者消费者问题,因为他比较接近资源管理器和多线程音频解码器的原型。

  比如,对于音频解码器,音频线程去流式的解码一段MP3格式的内存,就类似生产者生产产品的过程;而音频播放API(如OpenAL,OpenSL)通常需要的是PCM数据,也就是生产者生产的产品,所以播放逻辑充当消费者的角色,典型的生产者消费者问题。

  再对于资源管理器,加载Mesh和Texture类似生产单个Resource的过程,而相应的渲染逻辑去使用资源就相当于消费资源的过程,但不同的是最后当不再使用这个资源的时候,这个资源才会被释放,而非使用一次。

  今天抽时间,写了一个C++ windows版
多生产者多消费者的队列实现,pthread版估计等需要做跨平台的时候再做,如果想方便直接用OpenMP或者TBB也是可以的,但是对于轻量级引擎,自己实现资源加载器完全足够了。

  


#include <Windows.h>
#include <map>
#include <queue>

CRITICAL_SECTION g_cs; // mutex

HANDLE g_hEmptyBufferSemaphore;
HANDLE g_hFullBufferSemaphore;

#define INVALID -1

#define PRODUCER 5
#define CUSTOMER 5

#define NUM_COUNT 8
#define BUFF_SIZE 4

static std::queue<int> bufferQueue;
static std::map< DWORD,int > countMap;

bool ProducerFinish = false;

//设置控制台输出颜色
BOOL SetConsoleColor(WORD wAttributes)
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if (hConsole == INVALID_HANDLE_VALUE)
return FALSE;
return SetConsoleTextAttribute(hConsole, wAttributes);
}

DWORD WINAPI ProducerFunc(LPVOID param)
{

while(true)
{
WaitForSingleObject( g_hEmptyBufferSemaphore, INFINITE);

EnterCriticalSection(&g_cs);

DWORD threadId = GetCurrentThreadId();
if(countMap.find(threadId) == countMap.end())
countMap[threadId] = 0;

int productID = ++countMap[threadId];

bufferQueue.push( productID);
printf("生产者%d , 生产%d\n", threadId, productID);

if( productID == NUM_COUNT )
{
SetConsoleColor(FOREGROUND_RED);
printf("生产者%d生产完毕\n",GetCurrentThreadId());
SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);

LeaveCriticalSection(&g_cs);
ReleaseSemaphore(g_hFullBufferSemaphore, 1, NULL);

break;
}

LeaveCriticalSection(&g_cs);

ReleaseSemaphore(g_hFullBufferSemaphore, 1, NULL);
}

return NULL;
}

DWORD WINAPI CustomerFunc(LPVOID param)
{
while (true)
{
WaitForSingleObject( g_hFullBufferSemaphore, INFINITE);

EnterCriticalSection(&g_cs);

int buffer = -1;

if(!bufferQueue.empty())
{
buffer = bufferQueue.front();
bufferQueue.pop();
}

if(buffer != INVALID )
printf("消费者%d ,消费%d\n", GetCurrentThreadId() , buffer);

if( bufferQueue.empty() && ProducerFinish)
{
printf("消费者%d 结束\n",GetCurrentThreadId());
LeaveCriticalSection(&g_cs);

// 通知其他消费者可以结束了
ReleaseSemaphore( g_hFullBufferSemaphore, 1, NULL);
break;
}

LeaveCriticalSection(&g_cs);

ReleaseSemaphore( g_hEmptyBufferSemaphore, 1, NULL);
}

return NULL;
}

int _tmain(int argc, _TCHAR* argv[])
{
InitializeCriticalSection(&g_cs);

g_hEmptyBufferSemaphore = CreateSemaphore( NULL, 4, 4, NULL);
g_hFullBufferSemaphore = CreateSemaphore( NULL, 0, 4, NULL);

HANDLE producerThreads[PRODUCER];
HANDLE customerThreads[CUSTOMER];

// producer
for (int i = 0; i < PRODUCER; ++i)
{
producerThreads[i] = CreateThread( NULL, 0, ProducerFunc, NULL, NULL, NULL);
}

// customers
for (int i = 0; i < CUSTOMER; ++i)
customerThreads[i] = CreateThread( NULL, 0, CustomerFunc, NULL, NULL, NULL);

WaitForMultipleObjects( PRODUCER, producerThreads, TRUE, INFINITE);
ProducerFinish = true;

WaitForMultipleObjects( CUSTOMER, customerThreads, TRUE, INFINITE);

for (int i = 0; i < PRODUCER; ++i)
CloseHandle(producerThreads[i]);

for (int i = 0; i < CUSTOMER; ++i)
CloseHandle(customerThreads[i]);

CloseHandle(g_hEmptyBufferSemaphore);
CloseHandle(g_hFullBufferSemaphore);

DeleteCriticalSection(&g_cs);

countMap.clear();

return 0;
}

生产者消费者问题——C++ windows版 多生产者多消费者的队列实现

时间: 2024-08-05 10:28:53

生产者消费者问题——C++ windows版 多生产者多消费者的队列实现的相关文章

环形缓冲区的设计及其在生产者消费者模式下的使用(并发有锁环形队列)

1.环形缓冲区 缓冲区的好处,就是空间换时间和协调快慢线程.缓冲区可以用很多设计法,这里说一下环形缓冲区的几种设计方案,可以看成是几种环形缓冲区的模式.设计环形缓冲区涉及到几个点,一是超出缓冲区大小的的索引如何处理,二是如何表示缓冲区满和缓冲区空,三是如何入队.出队,四是缓冲区中数据长度如何计算. ps.规定以下所有方案,在缓冲区满时不可再写入数据,缓冲区空时不能读数据 1.1.常规数组环形缓冲区 设缓冲区大小为N,队头out,队尾in,out.in均是下标表示: 初始时,in=out=0 队头

可靠的Windows版Redis

副标题: 评论更精彩,教你怎么解决64位Windows版Redis狂占C盘的问题. MS Open Tech 技术团队最近花了很多时间来测试最新构建的Windows版Redis(可在 MS Open Tech Github 仓库下载). 当我们测试计划快要完成时,我们认为应该分享一些振奋人心的结果. 在压力测试的第一阶段,我们让Redis在Windows上进行各种测试,执行时间从1天到16天,以及简单的单master配置,到如下图所示的更复杂的配置,包括1个Master以及4个replicas.

交通银行 Java Socket 服务启动 管理 WINDOWS 版

按照交通银行提供的无界面启动方法试验了很多次,都没有成功,所以自己动手用C# 知识写了一个. 小工具可以判断 交通银行 JAVA SOCKET 服务是否启动,并可以启动/关闭服务 主要代码如下: 判断服务是否启动 引用 :using System.Management; SelectQuery selectQuery = new SelectQuery(“select * from Win32_Process where Name = ‘java.exe’”); object cmdLine =

三 APPIUM GUI讲解(Windows版)

本文本转自:http://www.cnblogs.com/sundalian/p/5629386.html APPIUM GUI讲解(Windows版) Windows版本的APPIUM GUI有以下图标或者按钮: ·Android Settings  - Android设置按钮,所有和安卓设置的参数都在这个里面 ·General Settings – 通用设置按钮 ·Developer Settings – 开发人员设置 ·About – 关于 Inspector – 元素侦测 ·Launch

Java 反编译工具 —— JAD 的下载地址(Windows版/Linux版/Mac OS 版)

Java 反编译工具 —— JAD 的下载地址. 各种版本哦! Windows版,Linux版,Mac OS 版,等等 下载地址: http://varaneckas.com/jad/ Java 反编译工具 -- JAD 的下载地址(Windows版/Linux版/Mac OS 版),布布扣,bubuko.com

在虚拟机linux环境下编译windows版adb fastboot

原文出自:http://blog.chinaunix.net/uid-20546441-id-1746200.html 我根据虚拟机编译遇到的问题进行一些添加 [前提条件] Linux Android源码完整 虚拟机磁盘空间100G左右(60G用来存放代码和编译后的文件) swap 30G左右,若太小会导致在编译后提示缺失文件 [具体步骤] 理论上,只要下一个windows版本的SDK,里面就自带了fastboot和adb工具. 但我最近确实遇到了一个需要在linux下编译出windows版本的

Windows版变色龙

打包安装版本更新源地址: http://www.insanelymac.com/forum/files/file/59-chameleon-22-svn/ 一.使用方法:1.安装Windows版变色龙RC5 Rev 875 for Windows2.自行决定是否替换C:\wowpc.iso为附件2.1svn_r1650_trunk的wowpc.iso(显示隐藏文件,才看得到)3.功能,同 Mac版变色龙,可启动主分区 + 逻辑分区的 Snow+Lion. 二.手动新建文件夹(在Mac硬盘)(在W

《coredump问题原理探究》Windows版 笔记

<coredump问题原理探究>Windows版 笔记 Debug 一.环境搭建 1.Win7捕获程序dump 2.Windbg符号表设置(Symbols Search Path) 二.WinDbg命令 三.函数栈帧 1.栈内存布局 2.栈溢出 3.栈的规律 4.定位栈溢出问题的经验方法 四.函数逆向 五.C内存布局 1.基本类型 2.数组类型 3.结构体 六.C++内存布局 1.类的内存布局 2.this指针 3.虚函数表及虚表指针 4.单继承 5.多继承(无公共基类) 七.STL容器内存布

HUSTOJ的Windows版评判内核(限制内存使用)

HUSTOJ的Windows版评判内核(一) 作者:游蓝海 个人主页:http://blog.csdn.net/you_lan_hai 2013.4.9 注:最新版本项目地址:https://github.com/NsLib/FreeJudger.新版FreeJudger,跟我之前写的这个已经完全不一样了,之前的这个废除.虽然现在工作忙,但我们会继续开发FreeJudger,直到功能完善,详见:HUSTOJ的Windows版评判内核(二) 在线评测系统(Online Judge System,O