views:

660

answers:

3

I would like to perform and atomic read of 64b aligned 64b data on x86 platform (Pentium or above guaranteed).

Is there a way to do this? (And no, I do not want to use a critical section or a mutex for this, I want this to be lock-free).

A: 

Use the Interlocked*() functions.

There's no read per se - but you can issue an Add() where you add 0.

Blank Xavier
Why do you assume he is using Windows?
Zifre
There is no Interlocked Add,Or/Xor on x86, only _InterlockedCompareExchange64 - see answer by Zifre
Suma
The question is currently flagged as "win32," so I think it's safe to assume the Windows functions are acceptable.
Max Lybbert
Hope the author added that - it wasn't there originally; and someone has removed the lock-free tag I added.
Blank Xavier
InterlockedAdd64 doesn't work on 32 bit platforms - you'll need to emulate it with InterlockedCompareExchange64.
Michael
+6  A: 

This page describes how to do it. Basically you just have to use lock cmpxchg8b.

Zifre
C++, not asm - he wants the OS provided wrappers.
Blank Xavier
@Blank Xavier, why do you think he wants OS provided wrappers? And how do you know what OS he is using?
Zifre
C++ tag. I don't know the OS though, so my Interlocked*() suggestion may not be useful to him.
Blank Xavier
I you're using MSVC++ check the _InterlockedCompareExchange compiler intrinsics. These are at least portable across windows platforms.
jn_
I don't think inline asm is really a problem. The only bad thing about asm is that it is not portable, but this is specifically about x86, so it doesn't matter. The functions given in the page I linked to would certainly be callable from C++.
Zifre
Great. Better than what I was doing before. Using Win API is can be written as follows: value = _InterlockedCompareExchange64(
Suma
@Zifre - you'd be surprised how much the interlocked C functions in Linux vary in their implementation across various system characteristics. Also of course as you touch upon, by using the OS provided functions, you get platform independence. You also can't get the implementation wrong.
Blank Xavier
Using OS functions, you get platform independence, but not OS independence. The OP specified x86 in the question, so I'm assuming OS independence would be more important that platform independence.
Zifre
x86 was mentioned since atomic 64 bit reads on x64 are a given..
Michael
+3  A: 

Use the Interlocked operations, here's some sample code:

LONGLONG AtomicRead(LONGLONG* p)
{
    return InterlockedCompareExchange64(p, 0, 0);
}

This does the compare exchange against zero and sets p to zero if it's already equal to zero -ie, it's a noop. InterlockedCompareExchange returns the original 64 bit value pointed to by p.

Michael
InterlockedAdd() adding 0 is better - CAS has more work to do and uses up more cycles.
Blank Xavier
According to MSDN InterlockedAdd is only supported on Itanium.Even on x86, lock add is only a 32-bit read.
Michael
I mean, InterlockedAdd64.
Michael