From: Bill Wade (bill.wade_at_[hidden])
Date: 2000-08-31 16:25:39


> From: William Kempf [mailto:sirwillard_at_[hidden]]

> You aren't suggesting that exchange is not useful, however,
> are you? It's really the only portable way to read/write an atomic_t
> value. (I'm not distinguishing exchange() from get()/set() because
> they are equivalent functionality with different interface
> signatures.)

L-value exchange (i.e. swap) is very useful and usually not available in a
fast atomic-over-both-arguments form.

R-value exchange (Atomic get-old-value-and-set-new-value) is useful, but is
a different operation from get(), and I still don't see how to use it to
implement get().

In procedural terms:

   // atomically return old value and set new value
   int AtomicGetAndSet(int& lvalue, int new_value)
   {
     Lock(lvalue);
     int result = lvalue;
     lvalue = new_value;
     Unlock(lvalue);
     return result;
   }

To me an atomic read looks like

  int AtomicGet(int& lvalue)
  {
    Lock(lvalue);
    int result = lvalue;
    Unlock(lvalue);
    return result;
  }

I think (please correct me if I have this wrong) you're saying to rewrite
Get as

  int AtomicGet(int& lvalue)
  {
    return GetAndSet(lvalue, lvalue);
  }

But that doesn't work. If we expand the function call we see

  int AtomicGet(int& a)
  {
    // Note that the second argument to GetAndSet is passed by value.
Simulate
    // this by invoking copy constructor before locking.
    int temp = a;
oops:
    Lock(a);
    int result = a;
    a = temp;
    Unlock(a);
    return result;
  }

If another thread does something (say Increment(a)) while Get() is at the
"oops" label, then Get will
  return the incremented a (that is ok, we had no guarantee which a we would
get).
  and put a back to its pre-incremented value (most certainly not ok for a
read).

In Win32 GetAndSet is named InterlockedExchange. The version of Get() that
works is a normal aligned 32-bit read (I sleep better if I make it a
volatile read).

Of course on Win32 you can write a working Get like this
  int AtomicGet(int& a)
  {
    int result = 0;
    InterlockedExchange(result, a);
    return result;
  }
But in this case the only thing InterlockedExchange did for you was to lock
result. To work it still needs integer copy construction to be atomic.