The riddle of atomic data transfer from process A to process B

The riddle of atomic data transfer from process A to process B

Omer Zak w1 at zak.co.il
Thu Apr 14 00:04:40 IDT 2011


On Wed, 2011-04-13 at 16:40 -0400, Ori Berger wrote:
> On 04/13/2011 09:41 AM, Omer Zak wrote:
> 
> > A full fledged queue would force the consuming process (process A) to
> > read and process all data written by the producing process (process M)
> > even when process A needs only the most recent value whenever it reads
> > process M's data.
> 
> I forgot how this scheme is called, but assuming you have some shared 
> memory between the processes, what you do is:
> 
> have value variable (e.g. "value") and counter variable ("counter")
> also shadow_value and shadow_counter

If the counter is one byte wide, then any updates to it would be atomic
by definition (of course, the context is that only process M ever
modifies it).

> initialize counter to 0 (any even number will do)
> 
> in process M:
> 
> atomic_increase counter; (or follow with memory_barrier())
> write value;
> atomic_increase counter; (or follow with memory_barrier())
> 
> in process A:
> 
> pre_counter = atomic_read counter; (or precede with memory_barrier())
> new_value = read value;
> post_counter = atomic_read counter; (or precede with memory_barrier())

I wondered whether it is enough to realize the counter using two bits.
However such a design won't protect process A from reading inconsistent
data if process M was updating data twice while process A was reading
the same data.
Even a bigger counter won't provide full protection as long as the
counter can overflow.  We need a way for process A to signal back to
process M that A is in middle of reading data, so process M should not
update it this time.

> if (pre_counter == post_counter) && (pre_counter%2 == 0), new_value has 
> been safely read; write it to "shadow_value", use that as value, (and 
> for good measure store pre_counter in "shadow_counter").
> 
> if pre_counter != post_counter, use "shadow_value" - and be aware that 
> your value is actually up to date only for "shadow_counter".

In this case, process A would simply yield control (equivalent to
putting process A in a loop, except that other processes would be
allowed to proceed meanwhile), as it hasn't read a new value this time.

> This is lock free in the sense that no process blocks waiting for the 
> other one. However, you may end up using an older value. You might put 
> 'A's reader in a loop, so that it retries until it manages to read an 
> up-to-date value.
> 
> Also, in a fully deterministic system, you might get to a situation 
> where A and B interlace in such a way that you *always* read the value 
> while it is being modified, so the shadow value never gets updated. In a 
> random system, the probability of being more than 'n' updates behind the 
> producer drops exponentially with n.

The ideal solution needs a mechanism to prevent this theoretical
possibility.

> Note that unlike CAS and friends, the "value" here can be any size 
> whatsoever - only the counter needs to be read/written atomically (or 
> otherwise synchronized through the memory barrier).

--- Omer


-- 
Shakespeare Monkeys: cat /dev/urandom | strings -n 16
My own blog is at http://www.zak.co.il/tddpirate/

My opinions, as expressed in this E-mail message, are mine alone.
They do not represent the official policy of any organization with which
I may be affiliated in any way.
WARNING TO SPAMMERS:  at http://www.zak.co.il/spamwarning.html




More information about the Linux-il mailing list