Using an NSRecursiveLock.
- (void) syncLockExample
{
for (unsigned i = 0; i < 1000; i++)
{
int r = rand();
[_recursiveLock lock];
// add a value if in the lower half of the range.
if (r <= RAND_MAX/2)
[_dataArray addObject:@(r)];
// if the value is odd, remove it.
if ([[_dataArray lastObject] intValue] % 2)
[_dataArray removeLastObject];
[_recursiveLock unlock];
}
}
Using a dispatch queue:
- (void) syncQueueExample
{
for (unsigned i = 0; i < 1000; i++)
{
int r = rand();
dispatch_sync(_dispatchQueue, ^{
// add a value if in the lower half of the range.
if (r <= RAND_MAX/2)
[_dataArray addObject:@(r)];
// if the value is odd, remove it.
if ([[_dataArray lastObject] intValue] % 2)
[_dataArray removeLastObject];
});
}
}
At first blush, there isn't much difference — hardly worth blogging about. However, these are trivial examples. From a maintenance perspective, the dispatch queue approach seems much better. Nobody can insert a return statement or remove a line of code that results in a lock left in the locked state, likely resulting in a deadlock. Aesthetically, the dispatch queue approach is better because the critical section is a block, a well-defined construct supported by the language (much like @synchronized). The lock version uses no feature of the language to define its scope.
There are some disadvantages to the dispatch queue approach. NSRecursiveLock, which is the NSLock I would normally choose for these scenarios, is forgiving of code in the critical section that itself calls more critical sections that share the same lock. Be warned that if you do the same with dispatch_sync, you will deadlock. However, if you're calling big swatches of code in such a synchronized state, you may want to rethink your locking altogether.
There are some disadvantages to the dispatch queue approach. NSRecursiveLock, which is the NSLock I would normally choose for these scenarios, is forgiving of code in the critical section that itself calls more critical sections that share the same lock. Be warned that if you do the same with dispatch_sync, you will deadlock. However, if you're calling big swatches of code in such a synchronized state, you may want to rethink your locking altogether.
No comments:
Post a Comment