This is a pet peeve of mine, to call that an "OS" feature. In all recent CPUs I know of, atomic ops are not a privileged operation, and there is absolutely nothing for the operating system to manage in a traditional sense. You don't trap into the kernel and have it compare-and-swap, you just, um, compare and swap.
Maybe your OS provides a convenient C API, but it is not "OS" functionality. It's just instructions on your CPU. You could just as well write them inline. In many common uses, that's what ends up happening - the atomic ops are put inline with the rest of your code.
But, a few points:
1. There is historically a distinction between "operating system" and "shared library shipping with the operating system". I think I am losing this battle though.
2. On a number of platforms (not sure if Apple's "OS atomics" concept counts here), the atomic wrappers are not even functions in a shared library. They may be declared inline in a header file. Or they may be compiler intrinsics, where the compiler doesn't generate any function call in any circumstances. Is that an "OS function"? Not really.
In either case #1 or case #2, I think "OS atomics" is a dumb name. We are really talking about CPU features, not OS features. If it doesn't generate a trap into kernel mode that doesn't very much sound like the OS doing the work.
Calling it "the OS" sounds more like a fundamental misunderstanding of dynamic linking and what it is. I hear so many variants of this core misunderstanding all over the place. Thinking that spinlocks need kernel help is one such manifestation.
How would you rephrase that? Just "low level atomic", "atomic"?
https://www.kernel.org/doc/Documentation/arm/kernel_user_hel...
The Linux kernel hack for that is actually kind of awesome. Notably, it's not a syscall and you don't enter the kernel to do them. Since pre-ARMv6 is always single core, it simply becomes a matter of detecting you are in the middle of an atomic op at interrupt time, and patching the result. This means the atomic op has to happen at a well-known (kernel-provided) address. Details here: http://lwn.net/Articles/314561/
I'm also aware of some older systems that needed kernel intervention for atomic ops. But on x86, ARMv6+, even no longer relevant arches like SPARC, POWER, ... this is not the case. It really is rare that the kernel needs to do this job these days.
Edit: ARMv6, not ARMv7, per the link I provided...
(I suspect it probably is, but fundamentally, @synchronize is implemented using compare and swap / other processor atomics, so it's probable that the difference is very slight - e.g. there's only a measurable difference if the thread is descheduled while holding a lock).
It's meant to be a somewhat-easy-to-digest introduction to lock-free design, where applicable.
What @synchronized ends up doing is far more complex — it has to be, to ensure the correctness of its purposes: https://github.com/opensource-apple/objc4/blob/master/runtim...
0: http://www.opensource.apple.com/source/objc4/objc4-646/runti...
The most Cocoa-compatible way of handling background execution of expensive procedures is always going to be best executed, quickest, using Grand Central Dispatch.
For example:
@interface Foo ()
@property (nonatomic) dispatch_queue_t backgroundQueue;
@end
@implementation Foo
- (BOOL) veryExpensiveMethod:(id)arg completion:(void (^)())completion {
dispatch_async(self.backgroundQueue, ^{
if (_counter++ > N) {
_counter--;
return NO;
}
// Critical section
_counter--;
return YES;
dispatch_async(dispatch_get_main_queue(), completion);
};
That will ensure every call to -veryExpensiveMethod is run in sequence, and won't require waiting on your end.These problems have been solved, better.
If you had read 'til the end you would have found multiple statements that OSAtomic* is merely an alternative. Not a silver bullet. Not the fastest.
From the conclusion:
"It's very important to understand that every example in this article could have legitimately been solved with different concurrency primitives — like semaphores and locks — without any noticeable impact to a human playing around with your app."
Also, "(...) is always going to be best executed, quickest, using GCD." is kind of a blanket statement. I'd be careful around the use of "always".
Also, why talk about performance and then make obj-c method calls...?
It's quite easy using NSProxy to create a throttler that will wrap any object, then you can abstract throttling from the behavior of the underlying object.
@interface Throttler : NSProxy {
dispatch_semaphore_t _semaphore;
id _object;
}
- initWithObject:(id)obj concurrentOperations:(int)ops;
@end
@implementation Throttler
- (id) initWithObject:(id)obj concurrentOperations:(int)ops {
if(self = [super init]){
_semaphore = dispatch_semaphore_create(ops)
_object = obj;
}
return self;
}
- (void) forwardInvocation:(NSInvocation*)invocation {
if(dispatch_semaphore_wait(_semaphore,0)){
@try {
[invocation setTarget: _object];
[invocation invoke];
}
@catch (NSException* e){
@throw e;
}
@finally {
dispatch_semaphore_signal(_semaphore);
}
return;
}
@throw [NSException
exceptionWithName:@"InsufficientResourceException"
reason:@"Insufficient Resource"
userInfo:nil];
}
@end
https://developer.apple.com/library/mac/documentation/Genera...