使用 MFC 同步的模板 FIFO 缓冲区
一个简单的模板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
对象时,您需要指定它的容量。这是可以在缓冲区中存储的最大对象数量(而不是以字节为单位的大小)。如果使用默认构造函数,则必须在任何 Read
或 Write
调用之前调用 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()
获取事件对象的句柄,并在 WaitForSingleObject
或 WaitForMultipleObjects
API 中使用它。
就这样。希望您喜欢它。