zoukankan      html  css  js  c++  java
  • 生产者消费者问题——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
    ", threadId, productID);
    
            if( productID == NUM_COUNT )
            {
                SetConsoleColor(FOREGROUND_RED);
                printf("生产者%d生产完毕
    ",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
    ", GetCurrentThreadId() , buffer);
    
            if( bufferQueue.empty() && ProducerFinish)
            {
                printf("消费者%d 结束
    ",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;
    }
  • 相关阅读:
    css如何去掉select原始样式
    Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL
    eclispe+maven+ssm+sql_server/mysql配置
    解决Missing artifact com.microsoft.sqlserver:sqljdbc4:jar:4.0问题
    eclipse alt+/智能提示错误问题
    去除input边框 input去除边框 去除input获取焦点时的蓝色外边框
    java对sql server的增删改查
    java连接sql server 2008
    卸载sql server 2008
    FTP的vsftpd.conf含义
  • 原文地址:https://www.cnblogs.com/singmelody/p/3779063.html
Copyright © 2011-2022 走看看