Re: Synchronization primitives (was:Re: Where is atomicqueue?)
Re: Synchronization primitives (was:Re: Where is atomicqueue?)
- Subject: Re: Synchronization primitives (was:Re: Where is atomicqueue?)
- From: Steve Sisak <email@hidden>
- Date: Tue, 29 Apr 2008 10:53:20 -0400
At 7:25 AM -0400 4/29/08, Army Research Lab wrote:
I understand the problems with them; however, the case I plan on supporting
generally locks for just long enough to write a value to a shared location,
with the values being 32 or 64 bit ints. That was why I got interested in
the various atomic functions. I know that they have a much higher
likelihood of being optimized than using pthread lock/write/unlock.
If this is all you're interested in, you can implement an atomic
update of a variable with one of the CompareAndSwap variants. (Note
that the 64-bit versions are only available to 64-bit code, and the
values must be on natural alignment, etc.)
int32_t *shared_value = <whatever>
int32_t new_value;
int32_t old_value;
do
{
old_value = *shared_value;
new_value = <insert your calculation>;
}
while (!OSAtomicCompareAndSwap32Barrier(old_value, new_value, shared_value);
At this point new_value has been successfully written and old_value
contains the
This is actually the basis for most of the OSAtomic*32 operations.
For 64-bit (or non-32-bit) values on a 32-bit system, you would have
to protect access using a semaphore, spinlock, etc.
> I would recommend you restrict yourself to supported interfaces.
I don't plan on doing otherwise. If I can't find a supported interface for
it, then I'll have to find another way.
You can implement a simple spinlock-like protection mechanism for
multiple values with compare and swap as well (I'll use the OSAtomic*
convenience functions and leave how to implement them using compare
and swap as an exercise),
------------
#define VALUE1_MASK (1 << 0)
#define VALUE2_MASK (1 << 1)
int32_t *shared_locks = <whatever>
int32_t old_locks;
do
{
old_locks = OSAtomicOr32Barrier(VALUE1_MASK, shared_locks);
// old_locks is the value of *shared_locks before
// you changed it -- if your bit wasn't set, then
// YOU changed it and now own the lock -- otherwise
// someone else set it and you don't
}
while (old_locks & VALUE1_MASK);
// do your stuff
old_locks = OSAtomicAnd32Barrier(~VALUE1_MASK, shared_locks);
------------
to implement non-blocking protection you would do:
old_locks = OSAtomicOr32Barrier(VALUE1_MASK, shared_locks);
if (!(old_locks & VALUE1_MASK))
{
// you got the lock -- do your stuff
old_locks = OSAtomicAnd32Barrier(~VALUE1_MASK, shared_locks);
}
------------
Read the relevant tecnnotes to determine if you need the barrier
versions or if you can get away with the non-barrier version.
When in doubt, use the barrier version, which forces all writes
started before it to complete before it. I think you can use
non-barrier for the unlock as long as you use barrier for the lock --
there's probably someone here who can correct me if I'm wrong -- but
the code above is safe.
You'd use a bit to protect each structure you wanted to update
atomically and more words as needed.
Hopefully this of use.
-Steve
*Disclaimer, this code was typed in Eudora, not a compiler. YMMV.
--
_________________________________________________________________________
Steve Sisak, CTO email@hidden
IOXperts, Inc. +1 617 876-2572
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden