AtomicInteger in Objective C

Prabal Chakraborty
Sep 8, 2018 · 4 min read

Since I wrote my first medium story about an implementation of ConcurrentHashMap in Objective C, it is only befitting that I be the one to introduce to you the ObjC implementation of Java’s AtomicInteger. Ok, enough fanfare!

TLDR; if you know what you want and are looking to quickly start using the AtomicNSInteger implementation, then start here.

Most iOS developers are already privy (and may be a tad bit jealous) to the fact that the Java SDK has a much richer library of out-of-the-box components — data structures, constructs, utilities etc. Some even argue that this lack of readymade stuff is a good thing for iOS developers, because you’ll learn the underlying system better by writing things from scratch. I don’t disagree but I also feel sometimes it is fetched too far, as in — isn’t the ease of development a thing to aspire for? Or is it not a basic software engineering principle to reuse components (even if they are not written by you) as much as possible so as to avoid the opportunity cost of rediscovering stuff that’s already out there? So I believe in finding (and keeping) any such ‘useful’ ObjC libraries I can find and very much sharing them with whoever may need them. Thus, AtomicNSInteger!

AtomicNSInteger, like its Java counterpart, is basically:

an NSInteger that can be updated atomically, such that when multiple threads are trying to read or update its value concurrently, it will hold on to its consistency in an expected manner

The class supports the common atomic operations like getAndIncrementValue, getAndDecrementValue, getAndAddValue and their counterparts incrementAndGetValue, decrementAndGetValue and addAndGetValue. Besides, it also supports operations compareTo:andSetValue and getAndSetValue.

Under the Hood
The implementation of AtomicNSInteger utilises the power of the OS-level functions OSAtomicCompareAndSwap32 and OSAtomicAdd32 (and their 64-bit counterparts). OSAtomicAdd32 adds two integer values atomically while the OSAtomicCompareAndSwap32 compares an integer value with the value stored at a memory location and based on the result, stores a new integer value in that memory location, all of it atomically. Let us see how we use these methods to implement the functionality supported by AtomicNSInteger.

We will look at the implementation of the method getAndSetValue which sets the value passed to the method and returns the value that was last set before the method returned:

@implementation KWAtomicInteger {
#if Is64BitArch
volatile int64_t _underlying;
#else
volatile int32_t _underlying;
#endif
}
- (NSInteger)getValue {
return _underlying;
}
- (NSInteger)getAndSetValue:(NSInteger)value {
while (true) {
NSInteger current = [self getValue];
if ([self compareTo:current andSetValue:value]) {
return current;
}
}
}
- (BOOL)compareTo:(NSInteger)expected andSetValue:(NSInteger)value {
#if Is64BitArch
return OSAtomicCompareAndSwap64(expected, value, &_underlying);
#else
return OSAtomicCompareAndSwap32(expected, value, &_underlying);
#endif
}

The method getAndSetValue runs a while loop (so do most other methods in this class) and keeps performing its desired action (in this case, setting the passed value) till it gets a desired result (in this case, the given value must be set). Inside the while loop, we first get the current value and keep it for returning, then we call the compareTo:andSetValue: method which essentially does this: check whether the current value is as expected, if yes, then set the new value.

Why are we checking the current value? Because if the current value isn’t what we expected it to be (based on our call to getValue) then some other thread is also trying to modify this value at the same time as the current thread and so we wouldn’t want to risk interference. So this is the key component of the atomicity of all such methods in this class — you read the value of a variable, then you change its value only if the value of the variable is still what you read in the previous line of code. The atomic OS level operation OSAtomicCompareAndSwap32 really helps to do exactly that — it checks if the value stored at the memory location (the 3rd argument) is the expected value (1st argument), and if that is the case, it sets the new value (2nd argument) in that memory location. Now, if the current value wasn’t found to be as expected, we consider that our operation (get and set) failed, so we try again from the beginning of the while loop.

Check out the complete code here. If you have any suggestions, comments, queries I would love to hear them — via medium, or via the github page.

PS: If you liked the article, please support it with claps 👏 below. Cheers!

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade