65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 MFC 同步的模板 FIFO 缓冲区

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (9投票s)

2009年9月9日

CPOL

2分钟阅读

viewsIcon

36187

downloadIcon

833

一个简单的模板FIFO缓冲。当新的数据被添加到FIFO的末尾时,发出事件脉冲。

引言

有时,当我们从一个模块向另一个模块传递数据时,会遇到与数量相关的问题。'接收者'对象需要X字节的数据,但'发送者'只能提供Y字节的部分。因此,'发送者'不能直接将数据传递给'接收者'。

还有另一种情况。'接收者'需要在确切的时间(如CD/DVD刻录设备)获取数据,但'发送者'不在乎。

因此,在这里,我们需要一个FIFO缓冲。FIFO代表先进先出。写入缓冲区的第一个数据是要读取并删除的第一个数据。然后,'接收者'可以根据自己的喜好读取尽可能多的数据(当然,如果FIFO中有足够的数据),并且在写入后随时读取。

CTypedFifo 是一个简单的模板类,提供了FIFO缓冲的功能,它用于存储任何类型的对象。它还具有与其他对象同步的能力。这个类声称是线程安全的。

使用代码

这是 CTypedFifo 类的声明

template <typename T>
class CTypedFifo
{
private:
    T * m_pW; // write pointer
    T * m_pR; // read pointer
    T * m_pBuf; // start address of the buffer
    T * m_pEnd; // end address of the buffer
    CCriticalSection m_cs; // sinchronicity
    CEvent m_eNewData; // pulsed when a write operation was performed
public:
    CTypedFifo();
    CTypedFifo(const UINT nCnt);
    ~CTypedFifo();

    BOOL Init(const UINT nCnt);
    BOOL Realloc(const UINT nCnt);
    void Free();

    // returns the count of the elements in the fifo
    int GetCount(); 

    // returns the maximum number of elements that can fit into the buffer
    int GetCapacity();

    int Read(T * pBuf, UINT nCnt);    
    void Write(const T * pBuf, UINT nCnt);
    void Drain(const UINT nCnt);
    DWORD WaitForNewData(DWORD dwMilliseconds = INFINITE);
    HANDLE GetNewDataEventHandle() const {return m_eNewData.m_hObject;}
private:
    int _Read(T * pBuf, UINT nCnt);
    int _GetCount() const;
    void _Drain(const UINT nCnt);
};

首先,当您构造一个 CTypedFifo 对象时,您需要指定它的容量。这是可以在缓冲区中存储的最大对象数量(而不是以字节为单位的大小)。如果使用默认构造函数,则必须在任何 ReadWrite 调用之前调用 Init(const UINT nCnt)

您可以通过调用 Realloc(const UINT nCnt) 随时更改缓冲区的容量。存储在缓冲区中的数据不会丢失。

您可以通过调用 GetCount() 检索存储的元素数量,如果您“忘记”了缓冲区的容量,则可以使用 GetCapacity() 获取它。

例如,如果您想将一系列 5 个 int 类型的数据写入缓冲区,以下代码将完成这项工作

CTypedFifo<int> intFifo;

... 

int seq[] = { 1, 3, 5, 7, 9 };

intFifo.Write(seq, 5);

稍后,当您需要读取其中的 3 个时

 ...

int read_seq[3];
int read_one;

intFifo.Read(read_seq, 3);
intFifo.Read(&read_one, 1);

所以现在,在 read_seq 中,我们有数字 { 1, 3, 5 },在 read_one 中,有 7。FIFO缓冲区中只剩下一个元素:9。

如果您不再需要缓冲区中的某些数据,您可以简单地调用 Drain(),它将消失。为了防止内存泄漏,请确保如果您在FIFO中存储指针,则删除它们指向的对象。

如果FIFO中没有数据,您可以使用 WaitForNewData(DWORD dwMilliseconds = INFINITE) 方法等待新数据。它将锁定调用线程,直到 dwMilliseconds 中的时间间隔过去,或者另一个线程将新数据写入缓冲区。

当您需要等待多个对象时,您可以通过调用 GetNewDataEventHandle() 获取事件对象的句柄,并在 WaitForSingleObjectWaitForMultipleObjects API 中使用它。

就这样。希望您喜欢它。

© . All rights reserved.