【造轮子】MFC实现BlockingQueue

最近任务需要在MFC下做多线程生产者消费者模式的东西,我找了半天貌似MFC没有类似Java里面BlockingQueue那样的工具(也许是我手残没找到)。

网上好像也有很多大佬去实现这个。但是我没仔细去找,看了看一些资料就想着造个轮子玩玩。

实现如下:

主要是利用CCriticalSection保护内置的std::list,然后用CEvent来实现生产者消费者的同步。

参考资料:http://stackoverflow.com/questions/6683356/c-templated-producer-consumer-blockingqueue-unbounded-buffer-how-do-i-end-el

接口文件:IBlockingQueue.h

 1 #pragma once
 2
 3 template <class T>
 4 class IBlockingQueue
 5 {
 6 public:
 7     virtual ~IBlockingQueue() {} // 为了让实现这个接口的类的析构函数能被正确调用,参考:http://blog.csdn.net/chaoguodong/article/details/6935524
 8     virtual int size() = 0;
 9     virtual T pop_front() = 0;
10     virtual T pop_back() = 0;
11     virtual void push_front(T val) = 0;
12     virtual void push_back(T val) = 0;
13     virtual bool empty() = 0;
14     virtual void stop() = 0;
15     virtual bool is_stop() = 0;
16 };

实现文件:BlockingQueue.h

#pragma once

#include <afxmt.h>
#include <list>

#include "Bridge.h"

// 参考资料:http://stackoverflow.com/questions/6683356/c-templated-producer-consumer-blockingqueue-unbounded-buffer-how-do-i-end-el

class StoppingException
{
public:
    LPCTSTR msg = _T("Stopping");
    StoppingException();
    ~StoppingException();
};

template <class T>
class CBlockingQueue : public IBlockingQueue<T>
{
    CCriticalSection m_cs; // 保护 m_lst
    CEvent m_emptyEvent; // m_lst 为空 就 reset,m_lst 不为空 就 set 放行
    std::list<T> m_lst;
    bool m_stop;
public:
    CBlockingQueue();
    CBlockingQueue(const CBlockingQueue<T>& obj);
    CBlockingQueue<T>& operator=(const CBlockingQueue<T>& obj);
    virtual int size();
    virtual T pop_front();
    virtual T pop_back();
    virtual void push_front(T val);
    virtual void push_back(T val);
    virtual bool empty();
    virtual void stop();
    virtual bool is_stop();
};

template <class T>
CBlockingQueue<T>::CBlockingQueue()
    : m_emptyEvent(FALSE, TRUE, NULL, NULL), m_stop(false) // 初始为RESET,不自动RESET
{}

template <class T>
CBlockingQueue<T>::CBlockingQueue(const CBlockingQueue<T>& obj)
    : m_emptyEvent(FALSE, TRUE, NULL, NULL), m_stop(false) // 初始为RESET,不自动RESET
{
    m_cs.Lock();
    obj.m_cs.Lock();
    m_lst = obj.m_lst;
    obj.m_cs.Unlock();
    m_cs.Unlock();
}

template <class T>
CBlockingQueue<T>& CBlockingQueue<T>::operator = (const CBlockingQueue<T>& obj)
{
    m_cs.Lock();
    obj.m_cs.Lock();
    m_lst = obj.m_lst;
    obj.m_cs.Unlock();
    m_cs.Unlock();
    return *this;
}

template <class T>
int CBlockingQueue<T>::size()
{
    m_cs.Lock();
    int sz = 0;
    sz = m_lst.size();
    m_cs.Unlock();
    return sz;
}
template <class T>
T CBlockingQueue<T>::pop_front()
{
    T val;
    bool done = false;
    while (!done && !is_stop())
    {
        ::WaitForSingleObject(m_emptyEvent.m_hObject, INFINITE);
        if (is_stop())
            throw StoppingException();
        m_cs.Lock();
        if (m_lst.empty())
        {

        }
        else
        {
            val = m_lst.front();
            m_lst.pop_front();
            if (m_lst.empty())
                m_emptyEvent.ResetEvent();
            done = true;
        }
        m_cs.Unlock();

    }
    return val;
}
template <class T>
T CBlockingQueue<T>::pop_back()
{
    T val;
    bool done = false;
    while (!done && !is_stop())
    {
        ::WaitForSingleObject(m_emptyEvent.m_hObject, INFINITE);
        if (is_stop())
            throw StoppingException();
        m_cs.Lock();
        if (m_lst.empty())
        {

        }
        else
        {
            val = m_lst.back();
            m_lst.pop_back();
            if (m_lst.empty())
                m_emptyEvent.ResetEvent();
            done = true;
        }
        m_cs.Unlock();

    }
    return val;
}
template <class T>
void CBlockingQueue<T>::push_front(T val)
{
    m_cs.Lock();
    m_lst.push_front(val);
    m_emptyEvent.SetEvent();
    m_cs.Unlock();
}
template <class T>
void CBlockingQueue<T>::push_back(T val)
{
    m_cs.Lock();
    m_lst.push_back(val);
    m_emptyEvent.SetEvent();
    m_cs.Unlock();
}
template <class T>
bool CBlockingQueue<T>::empty()
{
    m_cs.Lock();
    bool bEmpty = m_lst.empty();
    m_cs.Unlock();
    return bEmpty;
}
template <class T>
bool CBlockingQueue<T>::is_stop()
{
    m_cs.Lock();
    bool bStop = m_stop;
    m_cs.Unlock();
    return bStop;
}
template <class T>
void CBlockingQueue<T>::stop()
{
    m_cs.Lock();
    m_stop = true;
    m_emptyEvent.SetEvent();
    m_cs.Unlock();
}

实现文件:BlockingQueue.cpp

#include "BlockingQueue.h"

StoppingException::StoppingException() {}

StoppingException::~StoppingException() {}

测试文件:MyApp.h

#pragma once

#include <afxwin.h>

class CMyApp :
    public CWinApp
{
public:
    virtual BOOL InitInstance();
};

测试文件:MyApp.cpp

#include "MyApp.h"

#include "BlockingQueue.h"

using namespace std;

class CMainWindow :
    public CFrameWnd
{
public:
    CMainWindow();
    DECLARE_MESSAGE_MAP()
    afx_msg void OnClose();
};

CMainWindow::CMainWindow()
{
    Create(NULL, _T("The Hello Application"), WS_OVERLAPPED | WS_CAPTION |
        WS_SYSMENU | WS_MINIMIZEBOX | WS_THICKFRAME,
        CRect(32, 64, 352, 304));
}

CMyApp myApp;

// 共享的数据‘
IBlockingQueue<int>* pBQ = new CBlockingQueue<int>();

#define NUM_PRODUCER 9 // 生产者个数
#define NUM_CONSUMER 5 // 消费者个数

CWinThread* pThreadProducer[NUM_PRODUCER]; // 生产者线程
CWinThread* pThreadConsumer[NUM_CONSUMER]; // 消费者线程
HANDLE hConsumer[NUM_CONSUMER]; // 消费者HANDLE

// 生产
UINT Produce(LPVOID pParam)
{
    for (int i = 0; i < 10; ++i)
    {
        TRACE(_T("Producer[%d]Producing: %d\n"), ::GetCurrentThreadId(), i);
        pBQ->push_back(i);
        TRACE(_T("Producer[%d]Producing: %d\n"), ::GetCurrentThreadId(), i);
        pBQ->push_front(i);
        TRACE(_T("Producer[%d]Sleeping...\n"), ::GetCurrentThreadId());
        ::Sleep(1000);
    }
    TRACE(_T("Producer[%d]Exiting...\n"), ::GetCurrentThreadId());
    return 0;
}
// 消费
UINT Consume(LPVOID pParam)
{
    try {
        while (true)
        {
            TRACE(_T("Consumer[%d]Waiting...\n"), ::GetCurrentThreadId());
            int val = pBQ->pop_front();
            TRACE(_T("Consumer[%d]Consuming: %d\n"), ::GetCurrentThreadId(), val);
            val = pBQ->pop_back();
            TRACE(_T("Consumer[%d]Consuming: %d\n"), ::GetCurrentThreadId(), val);
        }
    }
    catch (StoppingException& e)
    {
        TRACE(_T("Consumer[%d]%s...\n"), ::GetCurrentThreadId(), e.msg);
    }
    TRACE(_T("Consumer[%d]Exiting...\n"), ::GetCurrentThreadId());
    return 0;
}
// 主线程(UI)
BOOL CMyApp::InitInstance()
{

    _CrtSetBreakAlloc(210);

    m_pMainWnd = new CMainWindow;
    m_pMainWnd->ShowWindow(m_nCmdShow);
    m_pMainWnd->UpdateWindow();

    // 共享的初始数据
    for (int i = 0; i < 100; ++i)
    {
        pBQ->push_back(i);
    }
    // 创建消费者线程
    for (int i = 0; i < NUM_CONSUMER; ++i)
    {
        CWinThread* pThread = ::AfxBeginThread(Consume, NULL, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
        pThread->m_bAutoDelete = FALSE;
        pThreadConsumer[i] = pThread;
        hConsumer[i] = pThread->m_hThread;
    }
    // 启动消费者线程
    for (int i = 0; i < NUM_CONSUMER; ++i)
    {
        pThreadConsumer[i]->ResumeThread();
    }
    // 创建生产者线程
    for (int i = 0; i < NUM_PRODUCER; ++i)
    {
        CWinThread* pThread = ::AfxBeginThread(Produce, NULL, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
        pThread->m_bAutoDelete = FALSE;
        pThreadProducer[i] = pThread;
    }
    // 启动生产者线程
    for (int i = 0; i < NUM_PRODUCER; ++i)
    {
        pThreadProducer[i]->ResumeThread();
    }

    return TRUE;
}

BEGIN_MESSAGE_MAP(CMainWindow, CFrameWnd)
    ON_WM_CLOSE()
END_MESSAGE_MAP()

// 退出主线程
void CMainWindow::OnClose()
{
    pBQ->stop();

    ::WaitForMultipleObjects(NUM_CONSUMER, hConsumer, TRUE, INFINITE);

    for (int i = 0; i < NUM_CONSUMER; ++i)
    {
        delete pThreadConsumer[i];
    }

    for (int i = 0; i < NUM_PRODUCER; ++i)
    {
        delete pThreadProducer[i];
    }

    delete pBQ;

    CFrameWnd::OnClose();
}
时间: 2024-11-11 08:32:43

【造轮子】MFC实现BlockingQueue的相关文章

python 造轮子(一)——序列与字典

虽然说造轮子很少用了,什么底层东西很少写,但是还是很想学扎实,还是好多东西还是的会,没有底层的支持,比较高级的库学起来还是很困难的. 序列的普遍用法: 1 #-*-coding:utf8-*- 2 3 #索引 4 l = [1,2,3,4] 5 t = (1,2,3,4) 6 d = {1:1,2:2,3:3,4:4} 7 8 9 print l[0] 10 print t[0] 11 print d[1] #键索引 12 13 #切片 14 15 print l[0:5] 16 print t

GitHub Android 最火开源项目Top20 GitHub 上的开源项目不胜枚举,越来越多的开源项目正在迁移到GitHub平台上。基于不要重复造轮子的原则,了解当下比较流行的Android与iOS开源项目很是必要。利用这些项目,有时能够让你达到事半功倍的效果。

1. ActionBarSherlock(推荐) ActionBarSherlock应该算得上是GitHub上最火的Android开源项目了,它是一个独立的库,通过一个API和主题,开发者就可以很方便地使用所有版本的Android动作栏的设计模式. 对于Android 4.0及更高版本,ActionBarSherlock可以自动使用本地ActionBar实现,而对于之前没有ActionBar功能的版本,基于Ice Cream Sandwich的自定义动作栏实现将自动围绕布局.能够让开发者轻松开发

我们为什么喜欢重新造轮子

不要重新造轮子,是英文don't re invite wheel的直译.什么是轮子呢,我们一般认为一个通用中间件或框架,和实际业务没有直接关系的代码,就是轮子.这些代码虽然不是实质的业务逻辑,但是在一个项目中往往是担当骨架的作用. 程序员新手的眼中,这些代码就是经验的象征.在很多项目组中,只有经验丰富的老程序员才有机会去设计和选择这些轮子.可以设计可重用的干货代码,也就成为很多对技术有追求的程序员的努力方向.有几年工作经验,在技术上寻求发展的程序员大多都会自己设计和实现一些经典的轮子,这也成为了

Hybrid App Development: 二、关于造轮子以及在Xcode iOS应用开发中加入Cordova

转载请注明出处:http://www.cnblogs.com/xdxer/p/4111552.html [ctrl+左键点击图片可以查看原图] 在上一篇关于Hybrid App Development的文章中,我讨论了一下在iOS下UIWebView的使用方法.但是光使用一个UIWebView所提供的功能还是完全不能满足我们的需求.   关于造轮子的思考: 在UIKit中的UIWebView虽然已经提供了很多功能了,比如JavaScript和Objc之间的通信.但是考虑到一个问题,如果在Hybr

避免重复造轮子的UI自动化测试框架开发

一懒起来就好久没更新文章了,其实懒也还是因为忙,今年上半年的加班赶上了去年一年的加班,加班不息啊,好了吐槽完就写写一直打算继续的自动化开发 目前各种UI测试框架层出不穷,但是万变不离其宗,驱动PC浏览器的基本上底层都是selenium,驱动无线app和浏览器基本是appium.monkey之类的,底层都是基于官方支持的自动化测试框架开发而来,然后上层又做了各种封装 首先在开始计划开发自动化时,第一步是了解目前已有的自动化开发技术,上面说了,最底层的就那几种,根据实际要去测试的业务需求选择合适的自

第27篇 重复造轮子---模拟IIS服务器

在写程序的时候,重复造轮子是程序员的一个大忌,很多人对重复造轮子持有反对的态度,但是我觉得这个造轮子的过程,是对于现有的知识的一个深入的探索的过程,虽然我们不可能把轮子造的那么的完善,对于现在有的东西是一个更好的理解和使用.   当你打开一个网页时,你会看到一个html页面的呈现,当然这是一个完整的Http的请求和响应的过程,无非是对HTML+CSS+JS一个综合的产物,在这个过程中浏览器请求数据的过程中会发出一个有一个格式的字符串(基于http协议生成的http请求报文),服务器在接收这样的一

Js造轮子,基础篇

在js中,只要不是在函数内部声明的函数都是全局变量了,如果代码量大的情况全局变量的污染是非常可怕的,所以需要造轮子声明自己的变量和自己的全局变量和函数方法 一,声明一个对象 先简单的声明一个对象tool={},这样就可以了,这样一个简单的全局对象就弄好了 二,声明方法和变量 这时候定义方法和变量就可以这样了 1 window.tool = {} 2 window.tool.cip = localStorage.cip; 3 4 //url 5 tool.urlHeader = 'http://1

何为造轮子?

著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:王子亭链接:http://www.zhihu.com/question/21818673/answer/20473677来源:知乎 显然,车轮子是圆形的,这是大家公认的,最合适的形状.而你非要发明另一种形状的轮子,这种行为就叫「重复发明轮子(Reinventing the wheel)」,即「造轮子」.「造轮子」的含义:明知道你做的不可能比前辈做得更好,却仍然坚持要做. 放到编程中,就是说业界已经有公认的软件或者库了,你明

【造轮子系列】转轮选择工具——WheelView的改进

在[造轮子系列]转轮选择工具--WheelView中,我详细记录了这个自定义控件的设计思路和相关数据的计算.由于本人能力有限,当时还留下了一些不足的地方,主要包括: 滑动的性能和流畅性有待提高,特别是快速滑动时的效果 没有实现循环滚动的效果 经过这一段时间的不断改进,现在基本上已经比较完美了,接近ios闹钟的滚轮时间选择器的效果了.下面结合代码,对比之前的版本,记录一下我做的这些改进. 效果图 源码 WheelView 核心计算思想的转变 性能优化说白了就是在得到相同结果的前提下进行最少的计算.

程序员为什么热衷造轮子

搜索一下"造轮子"或者"程序员为什么喜欢造轮子",会看到很多相关的讨论,这是个老生常谈的话题,很多人谈过了,谈了很多年.不过还是有再谈的必要. "造轮子"的含义: 明知道你做的不可能比前辈做得更好,却仍然坚持要做. 就软件开发而言,"造轮子"是指,"业界已经有公认的软件或者库了,却还坚持要自己做". 在软件开发过程中,有时你想造轮子老板却极力反对,有时你不想造轮子老板却坚持要造一个出来,为什么会有这种两极状