Last active
June 23, 2016 04:14
-
-
Save MadCoder/d33634fb28f1ed3c9d480f1887502320 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@implementation MyClass | |
+ (instancetype)sharedInstanceWithError:(NSError **)error | |
{ | |
static _Atomic(MyClass *) sMyClass; | |
MyClass *tmp = nil, *expected = nil; | |
#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__arm64__) | |
// this assumes that this platform has consume ordering | |
// for loads through dereferencing pointers, which both intel & arm have. | |
tmp = atomic_load_explicit(&sMyClass, memory_order_relaxed); | |
#else | |
// platforms where this isn't true need an acquire barrier | |
tmp = atomic_load_explicit(&sMyClass, memory_order_acquire); | |
#endif | |
if (tmp) { | |
return tmp; | |
} | |
// /!\ /!\ /!\ ACHTUNG MINEN /!\ /!\ /!\ | |
// for this whole trick to work, [[MyClass alloc] init] should not do any | |
// store to memory that will not be read from an expression derived from | |
// `sMyClass` without adding extra synchronization | |
// | |
// It also assumes that it's okay to create and try to setup several | |
// of these objects which isn't always the case | |
tmp = [[MyClass alloc] init]; | |
if (![tmp setupWithError:error]) { | |
return nil; | |
} | |
// try to publish our init, but we may lose that race | |
#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__arm64__) | |
if (atomic_compare_exchange_strong_explicit(&sMyClass, &expected, | |
tmp, memory_order_release, memory_order_relaxed)) { | |
// we won the init race | |
return tmp; | |
} | |
#else | |
if (atomic_compare_exchange_strong(&sMyClass, &expected, tmp)) { | |
// we won the init race | |
return tmp; | |
} | |
#endif | |
// we failed the init race, kill our instance | |
[tmp release]; | |
// return current value | |
return expected; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment