Skip to content

Instantly share code, notes, and snippets.

@hirad
Last active August 29, 2015 14:05
Show Gist options
  • Save hirad/0e24fc3a91be87317ab1 to your computer and use it in GitHub Desktop.
Save hirad/0e24fc3a91be87317ab1 to your computer and use it in GitHub Desktop.
An empty app to demonstrate race conditions in Objective-C and how to fix it with GCD.
@interface LHLAppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) NSNumber* counter; // will making this 'atomic' solve our problem?
@property (strong, nonatomic) dispatch_queue_t isolationQueue;
@property (strong, nonatomic) NSRecursiveLock* lock;
@end
@implementation LHLAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window setRootViewController:[UIViewController new]];
[self.window makeKeyAndVisible];
self.isolationQueue = dispatch_queue_create("com.Lighthouse-Labs.isolationQueue", 0);
self.lock = [NSRecursiveLock new];
self.counter = @0;
// let's get the default concurrent queue
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// let's create 4 blocks, each of which will increment our counter 1000 times
void (^asyncBlock)() = ^{
for (int i = 0 ; i < 1000; i++) {
[self incrementCounter];
}
NSLog(@"Finished increments. Current count: %ld",
(long)[self.counter integerValue]);
};
dispatch_async(q, asyncBlock);
dispatch_async(q, asyncBlock);
dispatch_async(q, asyncBlock);
dispatch_async(q, asyncBlock);
return YES;
}
-(void)incrementCounter
{
[self incrementCounterWithIsolationQueue];
}
-(void)incrementCounterUnsafe
{
self.counter = @([self.counter integerValue] + 1);
}
-(void)incrementCounterWithIsolationQueue
{
dispatch_async(self.isolationQueue, ^{
self.counter = @([self.counter integerValue] + 1);
});
}
-(void)incrementCounterWithLock
{
[self.lock lock];
self.counter = @([self.counter integerValue] + 1);
[self.lock unlock];
}
-(void)incrementCounterWithSynchronized
{
@synchronized(self) {
self.counter = @([self.counter integerValue] + 1);
}
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment