Spin Buffers
There has been a flurry of discussion recently over the buffering technique known as Spin Buffers. Much of this has centred on the author’s claim that they eliminate the need for synchronization. This has been met with scepticism by some, and discussed in more detail by MenTaLguY. This article lists the key assumptions made by the author, and then discusses systems where these apply. Finally, an attempt is made to find a niche for this technique – when can Spin Buffers be usefully applied?
Assumptions
The first assumption to note is that this technique should be applied to single-source/single-sink buffers. That is to say there should be only one ‘setter’ and one ‘getter’ using this buffer.
The second assumption is that in the following sequence, the italicised items happen in order:
1. Put the item into the write buffer.
2. If the next buffer is free, make the free buffer become the write buffer, and the current write buffer becomes free.
(There is a corresponding pair in the algorithm for retrieving data too.) When this assumption breaks down, we can find both the producer and consumer accessing the same underlying buffer whilst assuming that they have exclusive access. This assumption is the crux of the problem discussed by MenTaLguY.
None of these problems are insurmountable, but solving them requires the use of some form of synchronisation (from scattering volatile around to putting a lock or two in place). This seems to defeat the point of Spin Buffers, so instead, let’s find some applications where the assumptions hold true.
Embedded Systems
One place where efficiency of buffering techniques is often paramount is within the embedded systems world. Embedded systems often use (by modern PC standards) underpowered processors, lacking in such features as multiple processors or bus transaction reordering. This sort of environment is one in which the assumptions required for Spin Buffers can hold true. Not all embedded platforms are like this, but they are far from being rare.
In this sort of environment, a traditional ring buffer is a popular choice. By ensuring that data is written and read at the right times relative to the pointer increments, you can make a safe ring buffer without locks. This is based on the fact that memory writes occur in a specific order, which can be verified and confirmed on many embedded platforms.
Comparing Spin Buffers with Ring Buffers
So, given a platform where the Spin Buffer approach would work, and where a simple ring buffer would also work, why would you choose Spin Buffers over ring buffers? What differentiates Spin Buffers from ring buffers?
For Spin Buffers, you can avoid dealing with writing data over a buffer boundary (the buffer wrap problem), since you only need to write up to the end of each of the individual buffers. This is an advantage when writing multiple elements at once, but a fairly minor one in most cases.
Another difference is the total capacity for a given allocation of n elements for buffering. For a simple ring buffer, the total capacity is usually n-1 (an element is often sacrificed to simplify full/empty disambiguation). For Spin Buffers, the capacity is limited to 2/3 n, because at any one time the ‘free’ buffer must be empty. Sacrificing a third of your buffer is not always possible due to memory constraints.
The code required to implement a Spin Buffer compared to a ring buffer is more complex. Examining the author’s examples for both techniques shows that a Spin Buffer implementation is approximately twice as long as a ring buffer implementation. Whilst the execution time for Spin Buffers is likely to be marginally slower, I think a more important aspect is that greater complexity often leads to more bugs and higher maintenance costs. An example of this can be seen in the author’s implementation of the ‘put’ routine for the Spin Buffer. There is a bug which will cause a lock-up if the current write buffer ever becomes completely full.
Finally, if a partially full buffer is not written to for a period of time, then the entire Spin Buffer can seize up preventing the items in the last buffer used for writing from being read. The author highlights this in the caveats section, along with a workaround, but this adds additional complexity.
Conclusions
To conclude, I think that using Spin Buffers in certain environments can be safe. But in such environments, the advantages over a traditional ring buffer are slim and do not outweigh the costs in terms of code complexity and sacrificed capacity.
Like this:
Filed under: embedded, spin buffers | 1 Comment
Thanks for sharing excellent informations. Your web site is very cool. I’m impressed by the details that you have on this site. It reveals how nicely you understand this subject. Bookmarked this website page, will come back for extra articles. You, my friend, ROCK! I found just the information I already searched everywhere and simply could not come across. What a perfect web site.