C ++模板化生产者 - 消费者阻塞Queue,无界缓冲区:我如何优雅地结束? [英] C++ Templated Producer-Consumer BlockingQueue, unbounded buffer: How do I end elegantly?

查看:383
本文介绍了C ++模板化生产者 - 消费者阻塞Queue,无界缓冲区:我如何优雅地结束?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了一个BlockingQueue为了沟通两个线程。你可以说它遵循生产者 - 消费者模式,具有无界缓冲区。因此,我使用Critical Section和Semaphore实现它,如下:

I wrote a BlockingQueue in order to communicate two threads. You could say it follows the Producer-Consumer pattern, with an unbounded buffer. Therefore, I implemented it using a Critical Section and a Semaphore, like this:

#pragma once

#include "Semaphore.h"
#include "Guard.h"
#include <queue>

namespace DRA{
namespace CommonCpp{
template<class Element>
class BlockingQueue{
    CCriticalSection    m_csQueue;
    CSemaphore          m_semElementCount;
    std::queue<Element> m_Queue;
//Forbid copy and assignment
    BlockingQueue( const BlockingQueue& );
    BlockingQueue& operator=( const BlockingQueue& );
public:
    BlockingQueue( unsigned int maxSize );
    ~BlockingQueue();
    Element Pop();
    void Push( Element newElement );
};
}
}

//Template definitions
template<class Element>
DRA::CommonCpp::BlockingQueue<Element>::BlockingQueue( unsigned int maxSize ):
    m_csQueue( "BlockingQueue::m_csQueue" ),
    m_semElementCount( 0, maxSize ){
}

template<class Element>
DRA::CommonCpp::BlockingQueue<Element>::~BlockingQueue(){
    //TODO What can I do here?
}

template<class Element>
void DRA::CommonCpp::BlockingQueue<Element>::Push( Element newElement ){
    {//RAII block
        CGuard g( m_csQueue );
        m_Queue.push( newElement );
    }
    m_semElementCount.Signal();
}

template<class Element>
Element DRA::CommonCpp::BlockingQueue<Element>::Pop(){
    m_semElementCount.Wait();
    Element popped;
    {//RAII block
        CGuard g( m_csQueue );
        popped = m_Queue.front();
        m_Queue.pop();
    }
    return popped;
}

CGuard是CCriticalSection的RAII封装,它在破坏。 CSemaphore是一个Windows信号量的包装器。

CGuard is a RAII wrapper for a CCriticalSection, it enters it on construction and leaves it on destruction. CSemaphore is a wrapper for a Windows semaphore.

到目前为止,很好,线程是完美的沟通。然而,当生产者线程停止产生并结束,并且消费者线程已经消耗了所有东西时,消费者线程永远停留在Pop()调用上。

So far, so good, the threads are communicating perfectly. However, when the producer thread stops producing and ends, and the consumer thread has consumed everything, the consumer thread stays forever hung on a Pop() call.

告诉消费者结束优雅?我想到发送一个特殊的空元素,但它似乎太草率。

How can I tell the consumer to end elegantly? I thought of sending a special empty Element, but it seems too sloppy.

推荐答案

你最好使用事件而不是信号量。在添加时,在CS上锁定,并检查元素计数(存储到 bIsEmpty 局部变量)。添加到队列中,然后检查元素数量是否为空, SetEvent

You better use events instead of Semaphore. While adding, take lock on CS, and check element count (store into bIsEmpty local variable). Add into queue, then check if number of elements WAS empty, SetEvent!

然后检查它是否为空,然后 WaitForSingleObject - 一旦WFSO返回您获得队列中至少有一个项目。

On pop method, lock first, then check if it is empty, then WaitForSingleObject - as soon as WFSO returns you get that there is at least one item in queue.

请查看此文章

这篇关于C ++模板化生产者 - 消费者阻塞Queue,无界缓冲区:我如何优雅地结束?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆