1 - Problem

Suppose you have a device that makes readings and sends them to a computer through, for instance, a socket. If between two readings the computer has to do some calculations it is possible that, when the rate of the communication is higher, some data will be lost on the computer side.

2 - Solution

To solve this situation, you can create a thread in the computer side witch only task is to take the data out of the socket and put it in a buffer where the main program will go read it as soon as he is able to. Besides, as you don't know witch is the best length for the buffer, it will be even better if the buffer can grow as it is needed.

3 - Program

3.1 - Buffer

The buffer is a ring of a variable number of nodes each one with the following constitution:

A pointer to the next node in the ring

A pointer to a cell of fixed length where an item of data is stored

A character witch indicates the last operation done in the cell, a reading or a writing

Besides the nodes it also has a control structure, called "Ring", witch has the following constitution:

It begins by allocating NODES_ON_INIT nodes, then adjusts the pointers in the ring structure and makes the last created node to point at the first and finally fills the remaining of the ring structure.

3.2.2 - Write in the Buffer

The following function is used when it is needed to write in the buffer:

Here you can find two situations, the next node is marked as read or it is marked as wrote. In the former case there is no problem of writing over it, in the second case if you write over it you are loosing data because that node was not read yet.

As sought, in the former case you point to the next node, copy the data into the cell and mark the node as wrote. In the second case there are a few more steps to take. In order to write more data you are going to make the buffer bigger by adding to it some mode nodes. First because the buffer could be configured with a maximum size you ask if with the nodes you are about to add you don't reach that size yet. If it is ok you call the function that creates the nodes to add more NODES_ON_ADD nodes witch are created with the read flag, adjust the pointers and the function call itself because now the next node is already marked as read.

Here you ask again if the next node is marked as read or as wrote. In the former case there is nothing to read because all cells are marked with read. If it is marked as wrote then you can make a reading by copying the contents of the cell, adjusting the pointers and marking the node as read.

3.2.4 - Create Nodes

The simple but more complex function is to create nodes. The code to do that is:

The goal here is to create a finite number of nodes connected between them and with the first and last node opened. For that you create a cycle that, for the number of nodes that you want to create, begins by allocating space for the node, for the cell, marking the node as read and connecting it to the last created node. If it is the first node to be created (it will be the last in the queue because the queue grows to the back) it will point to NULL and the argument LST witch must points to the last node, will point to it. Finally the argument FST, that must point to the first node in the queue, points to the last created node.

3.2.5 - Delete the Buffer

When there is no more need for the buffer you must delete it. To do so you use the following code:

You begin by any node in the buffer, you take note of it and then you go by all nodes in the buffer freeing the space allocated to the cell and then the space allocated to the node until you reach the first node.

4 - Test

In order to test the program it was developed an application witch creates a thread that writes data to the buffer and the main program reads it and shows it on the screen. It was included a delay in the writing and a bigger one in the reading. This way the buffer gets full and it is possible to test it's growing. It was also included a maximum dimension for the buffer that when it is reached makes the application to end.

5 - Makefile

To build and test the whole application it was created a makefile that compiles all the modules. The application was tested under Cygwin environment but it will run as well under any Linux or Unix environment.

Comments and Discussions

The solution you discuss is flawed in respect
of the concurrent access of the buffer
by the reader and writer threads. Your solution
may lead to data corruption as a thread access
does not consider the locking of the shared resource
(i.e. the buffer). It is not enough to mark the
node as read or wrote.

I urge you to reconsider your solution.
If you used such solution in a software
in a production environment you may end up with
a "lossy" bug: your code may simply misteriously
ends up not processing at all some nodes.

In realtime processing systems (I work with by 7+ years)
it is customary to tackle such aspects with a technique
known as "circular Buffer" in a situation where
only one reader and one writer thread
are present.

For instance, you may want to take a look
at the following link:
http://www.codeproject.com/KB/threads/LockFree.aspx
Lock-Free Single-Producer - Single Consumer Circular Queue

If more than one reader / writer threads are present
you need to use explicit locking with a threaded queue.

I attach here a couple of C++ classes developed for such
purposes under Windows. You may use them under Linux
just replacing the Heap allocation functions with malloc / free
calls and using a mutex instead of a critical section
(available only under windows).

// Operations
public:
// Read the data
UINT32 GetTheData(void*&amp; 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);

// Check to see if the queue is full. We need to grow.
// Stop anyone from getting from the queue
::EnterCriticalSection( &amp;m_GetCriticalSection );
if ( new_add_index == m_GetIndex )
{
m_AddIndex = new_add_index;

There have been some mispellings
of the code by the cut and paste operations
(such as > and < symbols converted to HTML representations)
if you need those two classes just
email me:
federico.strati@tiscali.it

For the task you discuss, it is usually adopted a technique called "circular buffer" which has the merit of tacking care of locking issues between the writing and reading thread. Your solution does not take into account possible corruption of data as the writer and reader are in different threads.
There are excellent discussions already of the circular buffer in codeproject, you may want to take a look at these articles.

... unless until the problem is the one stated on the title and the solution must work in whatever condition.

A buffer can compensate for speed jitters, but, whatever the buffer size is, if the source spits data out faster that the sync elaborates them, the buffer will be in any case sooner or later filled up. That's the physics.

This "open-ring control" solution works only if you are granted that that the "average speed" of the source is always less than the "average" speed of the sync (or the amount of data produced by the source is always less than the sync's buffer size) and the time where the source get faster will not elapse more than the time required to fill the buffer.

If this cannot be granted by the physics of the process, you must either:
* allow the buffer to be full-filled and let some data to be lost (and let your app to live without them) or
* implement a bidirectional protocol between the source and the sync, allowing the sink to "pause" the source until more space is again available in the buffer, or ...
* use a faster computer or a more efficient calculation algorithm.

Thanks for your post.
It's true that when there is two or more threads accessing the same resource it is needed some kind of protection.
I thought of that but I couln't figure out where it was needed so I didn't put any but I agree that there are critic points where maybe they apply.
On the other hand I wouldn't like to put the locks where they are not needed because that way they will slow down the solution and fastness is one of my goals.
I would appreciate very much if you could help me pointing the place(s) where the locks are needed.
So, thanks again for your post and I will be waiting for your contrbution, bye,

For the task you discuss, it is usually adopted a technique called "circular buffer" which has the merit of tacking care of locking issues between the writing and reading thread. Your solution does not take into account possible corruption of data as the writer and reader are in different threads.
There are excellent discussions already of the circular buffer in codeproject, you may want to take a look at these articles.