$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
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.