6

I have googled for atomic increment and decrement operators on Mac OS X and found "OSAtomic.h", but it seems you can only use this in kernel space.

Jeremy Friesner pointed me at a cross-platform atomic counter in which they use assembly or mutex on OS X (as far as I understood the interleaving of ifdefs).

Isn't there something like InterlockedDecrement or atomic_dec() on OS X ?

Community
  • 1
  • 1
Anna B
  • 5,997
  • 5
  • 40
  • 52

4 Answers4

9

What makes you think OSAtomic is kernel space only? The following compiles and works fine.

#include <libkern/OSAtomic.h>
#include <stdio.h>

int main(int argc, char** argv) {
  int32_t foo = 1;
  OSAtomicDecrement32(&foo);
  printf("%d\n", foo);

  return 0;
}
wich
  • 16,709
  • 6
  • 47
  • 72
  • Geee, that's weird ! http://developer.apple.com/Mac/library/documentation/Darwin/Reference/KernelIOKitFramework/OSAtomic_h/index.html specifies OSDecrementAtomic, but I see no reference to OSAtomicDecrement32 even though it compiles fine. The kernel only thing was read on a mailing list archive... Thanks PS: If you know why the doc says differently from your code, I'd be glad to know. – Anna B Jan 23 '10 at 21:05
  • The `libkern` part does not imply _kernel mode_. They are offered as part of the kernel and driver development framework - see (http://developer.apple.com/mac/library/documentation/DriversKernelHardware/Reference/libkern_ref/index.html) for details. You might want to use the `OSAtomicDecrement32Barrier()` variant instead though. – D.Shawley Jan 23 '10 at 21:06
  • @D.Shawley: I don't need the memory barrier since I'm not allocating memory (I use the counter for a concurrent reference counting class). – Anna B Jan 23 '10 at 21:08
  • @Gaspard Bucher man is your friend ;) I just used `man atomic` – wich Jan 23 '10 at 21:24
  • @wich I've had locale issues with manpages (man pages not found) and got the habit to look at other sources (XCode, developer.apple.com). I'll try again. – Anna B Jan 23 '10 at 21:47
  • @Gaspard Bucher simply typing man $topic in any web search engine will get you the manpage as well, you could even define an alias to do the search directly in a text web browser ;) – wich Jan 23 '10 at 22:06
  • 1
    I don't think memory barriers are related to allocating memory... rather, they prevent the processor from re-ordering load and store operations across the barrier. I'm not sure whether they are needed for reference-counting, but I suspect they are (assuming you want your code to run correctly on multiprocessor Macs). Perhaps someone more knowledgable than I can confirm that, though. – Jeremy Friesner Jan 24 '10 at 05:37
  • @Jeremy memory barriers are related to memory allocation: "For example, if you want to initialize a shared data structure and then atomically increment a variable to indicate that the initialization is complete, then you must use OSAtomicIncrement32Barrier() to ensure that the stores to your data structure complete before the atomic add." (man atomic). Appart from this, ALL atomic operations are "thread and multiprocessor safe". – Anna B Jan 25 '10 at 08:29
  • @Gaspard, what you quoted doesn't mention memory allocation, only initialization. They are different things -- memory allocation involves requesting memory from the heap; initialization is just writing values into an already-allocated region of memory. – Jeremy Friesner Jan 25 '10 at 22:17
  • @Gaspard: no, memory barriers prevent the CPU and compiler from reordering memory accesses. And yes, you pretty much always need that. Otherwise you get an atomic increment, but no guarantee of *when* the variable is incremented relative to the rest of your program. – jalf Oct 01 '10 at 08:35
  • OSAtomicDecrement32, etc. are now deprecated. – Taylor Jul 14 '18 at 15:04
2

Currently, the recommendation is to use C++11's std::atomic.

Taylor
  • 5,871
  • 2
  • 30
  • 64
0

You could also check out Intel's Threaded Building Blocks for their atomic template class.

imaginaryboy
  • 5,979
  • 1
  • 32
  • 27
0

You can also use IncrementAtomic() and DecrementAtomic() via CoreServices:

#include <CoreServices/CoreServices.h>

int main(int argc, char** argv) 
{
  int val = 0;
  IncrementAtomic(&val);
  DecrementAtomic(&val);    

  return 0;
}

Note: the return value of these functions is the value of the integer before it is incremented, so if you want similar behavior to the Win32 InterlockedIncrement() and InterlockedDecrement() functions, you will need to create wrappers that +1 to the return value.

kgriffs
  • 4,080
  • 5
  • 37
  • 42