Click here to Skip to main content
15,910,234 members
Home / Discussions / C / C++ / MFC
   

C / C++ / MFC

 
GeneralRe: One genneral question on dual buffers design with multi-threading Pin
SAMZC15-Oct-10 23:42
SAMZC15-Oct-10 23:42 
AnswerRe: One genneral question on dual buffers design with multi-threading Pin
Cedric Moonen14-Oct-10 23:55
Cedric Moonen14-Oct-10 23:55 
GeneralRe: One genneral question on dual buffers design with multi-threading Pin
SAMZC15-Oct-10 20:37
SAMZC15-Oct-10 20:37 
GeneralRe: One genneral question on dual buffers design with multi-threading Pin
Rick York18-Oct-10 7:11
mveRick York18-Oct-10 7:11 
GeneralRe: One genneral question on dual buffers design with multi-threading Pin
SAMZC18-Oct-10 18:22
SAMZC18-Oct-10 18:22 
AnswerRe: One genneral question on dual buffers design with multi-threading Pin
Rajesh R Subramanian15-Oct-10 1:05
professionalRajesh R Subramanian15-Oct-10 1:05 
GeneralRe: One genneral question on dual buffers design with multi-threading Pin
SAMZC15-Oct-10 20:53
SAMZC15-Oct-10 20:53 
AnswerRe: One genneral question on dual buffers design with multi-threading Pin
federico.strati15-Oct-10 1:40
federico.strati15-Oct-10 1:40 
You're speking of a technique called flip-flop double buffering:
while one thread writes data to one buffer, the other thread
reads from the second buffer, then you swap buffers and start again.

This is in fact a circular buffer with only two entries.

I attach here two classes, one for the double buffer, the other for the
n-buffer circular ring buffer, both of them may be used to solve the
communication problem between the two threads.

Note that the circular buffer works with pointers to buffers that you
allocate and free outside the buffer itself, while the double buffer
works with copying data from outside buffers to buffers preallocate
inside it.

You may also wish to get a read of the article:
Lock-Free Single-Producer - Single Consumer Circular Queue for the circular ring buffer

--- double buffer include ---
#ifndef DOUBLE_BUFFER_H
#define DOUBLE_BUFFER_H

#include <afx.h>
#include <afxwin.h>

class CDoubleBuffer
{
public:
   CDoubleBuffer( unsigned int unAlloc = 0x000FFFFF );
   ~CDoubleBuffer(void);

   void Write(void* pBuf, unsigned int unBytesTo);
   void Read (void* pBuf, unsigned int unBytesFrom);

private:
   void** pAlloc;
   unsigned int unRead;
   unsigned int unWrite;
   unsigned int unSize;
};

#endif // ! defined (DOUBLE_BUFFER_H)

--- double buffer include end ---

--- double buffer body ---
#include "stdafx.h"
#include "DoubleBuffer.h"

CDoubleBuffer::CDoubleBuffer( unsigned int unAlloc /* = 0x000FFFFF */ )
{
   pAlloc = NULL;
   pAlloc = (void **) ::HeapAlloc(::GetProcessHeap(), 0, 2 * sizeof(void*));
   if (!pAlloc) throw;
   pAlloc[0] = NULL;
   pAlloc[0] = (void *) ::HeapAlloc(::GetProcessHeap(), 0, unAlloc * sizeof(BYTE));
   if (!pAlloc[0]) throw;
   pAlloc[1] = NULL;
   pAlloc[1] = (void *) ::HeapAlloc(::GetProcessHeap(), 0, unAlloc * sizeof(BYTE));
   if (!pAlloc[1]) throw;
   ::FillMemory((void*) pAlloc[0], unAlloc, 0);
   ::FillMemory((void*) pAlloc[1], unAlloc, 0);

   unRead  = 0;
   unWrite = 0;
   unSize = unAlloc;
}

CDoubleBuffer::~CDoubleBuffer(void)
{
   ::HeapFree(::GetProcessHeap(), 0, pAlloc[0]);
   ::HeapFree(::GetProcessHeap(), 0, pAlloc[1]);
   ::HeapFree(::GetProcessHeap(), 0, pAlloc);
}

void CDoubleBuffer::Write(void* pBuf, unsigned int unBytesTo)
{
   unsigned int unTryWrite = (unWrite++)%2;
   while( unRead == unTryWrite ) { ::Sleep(10); }
   ::MoveMemory( pAlloc[unTryWrite], pBuf, __min(unBytesTo,unSize) );
   unWrite = unTryWrite;
}

void CDoubleBuffer::Read(void* pBuf, unsigned int unBytesFrom)
{
   while( unRead == unWrite ) { ::Sleep(10); }
   unsigned int unTryRead = (unRead++)%2;
   ::MoveMemory(pBuf, pAlloc[unTryRead], __min(unBytesFrom,unSize));
   unRead = unTryRead;
}

--- double buffer body end ---

--- circular buffer include ---
// Light Weight Circular Buffer with elementary locking

#ifndef CBUFFER_H
#define CBUFFER_H

#if _MSC_VER > 1000
#pragma warning (disable: 4786)
#pragma warning (disable: 4748)
#pragma warning (disable: 4103)
#endif /* _MSC_VER > 1000 */

#include <afx.h>
#include <afxwin.h>

// Default number of elements in buffer
#define CBUFFER_NELEM		      0x0000FFFF

// The Circular Buffer errors
#define CBUFFER_ERRCODE_OK               0
#define CBUFFER_ERRCODE_NO_MEMORY        1
#define CBUFFER_ERRCODE_READ_ERROR       2
#define CBUFFER_ERRCODE_WRITE_ERROR      3
#define CBUFFER_ERRCODE_NO_DATA          4

#define CBUFFER_NULL_PTR                 0xFFFFFFFF

class CCircBuffer
{
// Constructors, Destructor
public:
   CCircBuffer(UINT32 unElements = CBUFFER_NELEM);
   ~CCircBuffer(void);

// Operations
public:
   // Read  the data
   UINT32 GetTheData(void*& lpData);
   // Write the data
   UINT32 SetTheData(void*  lpData);
   // Increment the read pointer
   UINT32 IncTheReadPtr(void);
   // Increment the write pointer
   UINT32 IncTheWritePtr(void);
   // Check if there is any space for reading data
   bool IsReadyForRead(void);
   // Check if there is any space for writing new data
   bool IsReadyForWrite(void);
   // Get the last known value for the read pointer
   UINT32 GetLastReadPtr(void);
   // Get the last known value for the write pointer
   UINT32 GetLastWritePtr(void);

// Attributes
private:
   // The Circular Buffer of void pointers
   void**  TheCircularBuffer;
   SIZE_T unElems;
   // The Circular Buffer pointers
   UINT32 unReadPtr, unWritePtr;
   // The Circular Buffer last error
   UINT32 unLastErrorCode;
};

#endif /* ! defined(CBUFFER_H) */

--- circular buffer include end ---

--- circular buffer body ---
#include "StdAfx.h"
#include "CircBuffer.h"

CCircBuffer::CCircBuffer(UINT32 unElements /* = CBUFFER_NELEM */)
{
   unLastErrorCode = CBUFFER_ERRCODE_OK;
   // Allocate the Buffer
   unElems = (SIZE_T) unElements;
   if ( unElems >= CBUFFER_NULL_PTR ) // max size
      unElems = CBUFFER_NULL_PTR - 1;
   TheCircularBuffer = (void **) HeapAlloc(GetProcessHeap(), 0, unElems * sizeof(void*));
   // Cannot allocate memory
   if(!TheCircularBuffer)
   {
      unLastErrorCode = CBUFFER_ERRCODE_NO_MEMORY;
   }
   else
   {
      SecureZeroMemory(TheCircularBuffer, sizeof(TheCircularBuffer));
   }
   // Set Pointers
   unReadPtr = unWritePtr = 0;
}

CCircBuffer::~CCircBuffer(void)
{
   unLastErrorCode = CBUFFER_ERRCODE_OK;
   BOOL bResult = HeapFree(GetProcessHeap(), 0, TheCircularBuffer);
   if( bResult != TRUE )
   {
      unLastErrorCode = CBUFFER_ERRCODE_NO_MEMORY;
   }
}

// Operations

// Read the data
UINT32 CCircBuffer::GetTheData(void*& lpData)
{
   unLastErrorCode = CBUFFER_ERRCODE_OK;
   // Check if there is any data to be read in the buffer
   if( ! IsReadyForRead() )
   {
      // No data to be read in buffer
      unLastErrorCode = CBUFFER_ERRCODE_NO_DATA;
      return CBUFFER_NULL_PTR;
   }
   // Get the data
   lpData = (void*) TheCircularBuffer[unReadPtr];
   // Increment the read pointer
   unReadPtr++;
   if( unReadPtr >= unElems )
      unReadPtr = 0;	// Restart
   return unReadPtr;
}

// Write the data
UINT32 CCircBuffer::SetTheData(void* lpData)
{
   unLastErrorCode = CBUFFER_ERRCODE_OK;
   // Check if there is any way of writing the data
   if( ! IsReadyForWrite() )
   {
      // No way to write data in Buffer
      unLastErrorCode = CBUFFER_ERRCODE_NO_DATA;
      return CBUFFER_NULL_PTR;
   }
   // Set the data
   TheCircularBuffer[unWritePtr] = (void*) lpData;
   // Increment the write pointer
   unWritePtr++;
   if( unWritePtr >= unElems )
      unWritePtr = 0; // Restart
   return unWritePtr;
}

// Increment the read pointer
UINT32 CCircBuffer::IncTheReadPtr(void)
{
   unLastErrorCode = CBUFFER_ERRCODE_OK;
   // Check if there is any data to be read in the buffer
   if ( ! IsReadyForRead() )
   {
      // No data available to be read
      unLastErrorCode = CBUFFER_ERRCODE_NO_DATA;
      return CBUFFER_NULL_PTR;
   }
   // Increment the read pointer
   unReadPtr++;
   if( unReadPtr >= unElems )
      unReadPtr = 0; // restart
   return unReadPtr;
}

// Increment the write pointer
UINT32 CCircBuffer::IncTheWritePtr(void)
{
   unLastErrorCode = CBUFFER_ERRCODE_OK;
   // Checks if there is any way of writing the data
   if( ! IsReadyForWrite() )
   {
      // No way to write data
      unLastErrorCode = CBUFFER_ERRCODE_NO_DATA;
      return CBUFFER_NULL_PTR;
   }
   // Increment the write pointer
   unWritePtr++;
   if( unWritePtr >= unElems )
      unWritePtr = 0; // restart
   return unWritePtr;
}

// Check if there is any way of reading the data
bool CCircBuffer::IsReadyForRead(void)
{
   unLastErrorCode = CBUFFER_ERRCODE_OK;
   // Check if there is any way of reading the data
   // The test pointer
   UINT32 unCheckReadPtr = unReadPtr;
   if( unCheckReadPtr >= unElems )
      unCheckReadPtr = 0;	// Restart
   if( unCheckReadPtr == unWritePtr )
   {
      // No way to read data
      unLastErrorCode = CBUFFER_ERRCODE_NO_DATA;
      return false;
   }
   return true;
}

// Check if there is any space for writing new data
bool CCircBuffer::IsReadyForWrite(void)
{
   unLastErrorCode = CBUFFER_ERRCODE_OK;
   // Checks if there is any way of writing the data
   // Increment the test pointer
   UINT32 unCheckWritePtr = unWritePtr;
   unCheckWritePtr++;
   if( unCheckWritePtr >= unElems )
      unCheckWritePtr = 0;	// Restart
   if( unCheckWritePtr == unReadPtr )
   {
      // No way to write data
      unLastErrorCode = CBUFFER_ERRCODE_NO_DATA;
      return false;
   }
   return true;
}

// Get the last known value for the read pointer
UINT32 CCircBuffer::GetLastReadPtr(void)
{
   unLastErrorCode = CBUFFER_ERRCODE_OK;
   return unReadPtr;
}

// Get the last known value for the write pointer
UINT32 CCircBuffer::GetLastWritePtr(void)
{
   unLastErrorCode = CBUFFER_ERRCODE_OK;
   return unWritePtr;
}

--- circular buffer body end ---

Hope that helps

Cheers
Federico

federico-strati [at] libero [dot] it
GeneralRe: One genneral question on dual buffers design with multi-threading Pin
SAMZC15-Oct-10 20:51
SAMZC15-Oct-10 20:51 
GeneralRe: One genneral question on dual buffers design with multi-threading Pin
SAMZCN15-Oct-10 23:31
SAMZCN15-Oct-10 23:31 
GeneralRe: One genneral question on dual buffers design with multi-threading Pin
federico.strati17-Oct-10 20:45
federico.strati17-Oct-10 20:45 
GeneralRe: One genneral question on dual buffers design with multi-threading Pin
SAMZC16-Oct-10 7:57
SAMZC16-Oct-10 7:57 
GeneralRe: One genneral question on dual buffers design with multi-threading Pin
federico.strati17-Oct-10 20:50
federico.strati17-Oct-10 20:50 
GeneralRe: One genneral question on dual buffers design with multi-threading Pin
SAMZCN18-Oct-10 2:16
SAMZCN18-Oct-10 2:16 
GeneralRe: One genneral question: there were errors in my code !!! Pin
federico.strati19-Oct-10 22:25
federico.strati19-Oct-10 22:25 
QuestionHello calling function between two different processes Pin
nah133714-Oct-10 22:42
nah133714-Oct-10 22:42 
AnswerRe: Hello calling function between two different processes Pin
CPallini14-Oct-10 22:47
mveCPallini14-Oct-10 22:47 
AnswerRe: Hello calling function between two different processes Pin
Rajesh R Subramanian15-Oct-10 0:52
professionalRajesh R Subramanian15-Oct-10 0:52 
QuestionEncrypt / Decrypt a file Pin
mesajflaviu14-Oct-10 21:51
mesajflaviu14-Oct-10 21:51 
AnswerRe: Encrypt / Decrypt a file Pin
CPallini14-Oct-10 22:32
mveCPallini14-Oct-10 22:32 
Questionstring question Pin
sadas232341s14-Oct-10 8:20
sadas232341s14-Oct-10 8:20 
AnswerRe: string question Pin
Luc Pattyn14-Oct-10 8:36
sitebuilderLuc Pattyn14-Oct-10 8:36 
QuestionRe: string question Pin
David Crow14-Oct-10 9:15
David Crow14-Oct-10 9:15 
AnswerRe: string question Pin
CPallini14-Oct-10 9:27
mveCPallini14-Oct-10 9:27 
GeneralRe: string question Pin
Luc Pattyn14-Oct-10 9:34
sitebuilderLuc Pattyn14-Oct-10 9:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.