Synchronization callbacks - block vs GCD queue - objective-c

I am new to asynchronous callbacks and have been given differing advice. I need to perform asynchronous callbacks and after many hours of research I still do not know if I should use blocks or GCD and queues. Any pointers would be welcome.
OK. So what I was really asking is:
"in order to use an 'asynchronous' callbacks, do I need to use GCD and queues?"
What I am gathering from the answers is that the answer is YES. Definitely GCD and queues inside of blocks.
My confusion stemmed from the fact that I had been given the direction that all I needed was a block, like the code below:
[UIView animateWithDuration:.4f
animations:^{
flashView.alpha = 0.f;
}
completion:^(BOOL finished){
[flashView removeFromSuperview];
}
];
But what I am seeing in the answers here is that the above block in not sufficient for making 'asynchronous' callbacks. Instead I DO in-fact need to use GCD and queues inside a block, like the code below:
- (void)invokeAsync:(id (^)(void))asyncBlock resultBlock:(void (^)(id))resultBlock errorBlock:(void (^)(id))errorBlock {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id result = nil;
id error = nil;
#try {
result = asyncBlock();
} #catch (NSException *exception) {
NSLog(#"caught exception: %#", exception);
error = exception;
}
// tell the main thread
dispatch_async(dispatch_get_main_queue(), ^{
NSAutoreleasePool *secondaryPool = [[NSAutoreleasePool alloc] init];
if (error != nil) {
errorBlock(error);
} else {
resultBlock(result);
}
[secondaryPool release];
});
[pool release];
});
}

An asynchronous callback is one where your current thread keeps executing statements, and you detach the execution of code in a different thread to be ran later.
There are several technologies to accomplish this. On this example I'm calling the method cacheImage:, with parameter image (just an example) in 4 different asynchronous ways.
// 1. NSThread
[NSThread detachNewThreadSelector:#selector(cacheImage:) toTarget:self withObject:image];
// 2. performSelector...
[self performSelectorInBackground:#selector(cacheImage:) withObject:image];
// 3. NSOperationQueue
NSInvocationOperation *invOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(cacheImage:) object:image];
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
[opQueue addOperation:invOperation];
// 4. GCD
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self cacheImage:image];
});
By far the more simple way is to use GCD because it already has a thread ready for you to use, instead having to create it yourself with the other options.
However, because blocks are implemented as objects, you could indeed use blocks without GCD, for example:
// block definition
typedef void (^hello_t)();
// method that uses a block as parameter
-(void) runBlock:(hello_t)hello {
hello();
}
// asynchronous execution of a block
[NSThread detachNewThreadSelector:#selector(runBlock) toTarget:self withObject:^(){
NSLog(#"hi");
}];
PS: you don't need to use NSAutoreleasePool manually unless you create many many objects and you want to free memory immediately. Also, #try #catch are rarely used in Objective-C

Not any point of confusion here. GCD also has a block execution.
GCD API, which supports the asynchronous execution of operations at the Unix level of the system.
Block objects are a C-level syntactic and runtime feature. They are similar to standard C functions, but in addition to executable code they may also contain variable bindings to automatic (stack) or managed (heap) memory. A block can therefore maintain a set of state (data) that it can use to impact behavior when executed.
Apple designed blocks with the explicit goal of making it easier to write programs for the Grand Central Dispatch threading architecture, although it is independent of that architecture and can be used in much the same way as closures in other languages. Apple has implemented blocks both in their own branch of the GNU Compiler Collection and in the Clang LLVM compiler front end. Language runtime library support for blocks is also available as part of the LLVM project.
Therefore you can use any one of them given you same functionality.

Related

iOS concurrency: NSOperationQueue and ARC issue

I am currently implementing a multithreaded application and I encounter a strange race condition (leading to an ARC problem: error for object 0x7f8bcbd6a1c0: pointer being freed was not allocated).
The app creates multiple NSOperations, each one is downloading and processing information. As in every one of these NSOperations an error may occur (e.g., the web service is not available), I want to propagate the error up so I can handle it. However, I seem to encounter a race condition and the operations try to access invalid memory.
A minimalistic example which shows the memory access problem is the following one:
- (void) createError: (NSError**) err {
*err = [[NSError alloc] initWithDomain:#"Test" code:12345 userInfo:nil];
}
- (void)viewDidLoad {
[super viewDidLoad];
__block NSError *globalError = nil;
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSOperation *op = nil;
for (int i=0; i<10; i++) {
op = [NSBlockOperation blockOperationWithBlock:^{
NSError *err = nil;
[self createError:&err];
// This loop increases the chance to get the race condition
for (int j=0; j<10000;j++) {
#synchronized(globalError) {
globalError = err;
}
}
}];
[queue addOperation:op];
}
[queue waitUntilAllOperationsAreFinished];
if (globalError) {
NSLog(#"An error occured in at least one of the operations");
}
}
Whenever I run this program, I get an exception. Mostly it is error for object 0x7fc0b860e860: pointer being freed was not allocated, however, sometimes I also got an EXC_BAD_ACCESS (code=EXC_I386_GPFLT) break in the debugger.
I have added the for-Loop over 10000 iterations only to increase the chance that the race condition occurs. If I leave it, the error only occurs in rare occasions (but still has to be fixed, obviously I am doing something wrong here).
The #synchronized directive uses the object you pass to control the synchronization, so, as you note, you're trying to synchronize on nil. And even if it wasn't nil, the object referenced by the #synchronized directive is a different object every time, largely defeating the attempt to synchronize.
The easiest change is to use #synchronized(self), instead. Or, create a NSLock object and then lock and unlock it when you access globalError. Or, if this was a high demand situation, use GCD queue (either serial queue or reader-writer pattern).

Barrier operations in NSOperationQueue

How can we implement dispatch_barrier_async's equivalent behavior using NSOperationQueue or any user-defined data-structure based on NSOperationQueue?
The requirement is, whenever a barrier operation is submitted it should wait until all non-barrier operations submitted earlier finish their execution and blocks other operations submitted after that.
Non-barrier operations should be able to perform concurrently.
Barrier operations should execute serially.
NB: Not using GCD,as it doesn't provide(or atleast difficult) much access over the operations, like cancelling single operation, etc.
This is more or less what jeffamaphone was saying, but I put up a gist that should, in rough outline, do what you ask.
I create a NSMutableArray of NSOperationQueues, which serves as a "queue of queues". Every time you add a BarrierOperation object, you tack a fresh suspended op queue on the end. That becomes the addingQueue, to which you add subsequent operations.
- (void)addOperation:(NSOperation *)op {
#synchronized (self) {
if ([op isKindOfClass:[BarrierOperation class]]) {
[self addBarrierOperation:(id)op];
} else {
[[self addingQueue] addOperation:op];
}
}
}
// call only from #synchronized block in -addOperation:
- (void)addBarrierOperation:(BarrierOperation *)barrierOp {
[[self addingQueue] setSuspended:YES];
for (NSOperation *op in [[self addingQueue] operations]) {
[barrierOp addDependency:op];
}
[[self addingQueue] addOperation:barrierOp];
// if you are free to set barrierOp.completionBlock, you could skip popCallback and do that
__block typeof(self) weakSelf = self;
NSOperation *popCallback = [NSBlockOperation blockOperationWithBlock:^{
[weakSelf popQueue];
}];
[popCallback addDependency:barrierOp];
[[self addingQueue] addOperation:popCallback];
[[self addingQueue] setSuspended:NO];
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
[opQueue setSuspended:YES];
[_queueOfQueues addObject:opQueue]; // fresh empty queue to add to
}
When one NSOperationQueue finishes, it gets popped and the next one starts running.
- (void)popQueue
{
#synchronized (self) {
NSAssert([_queueOfQueues count], #"should always be one to pop");
[_queueOfQueues removeObjectAtIndex:0];
if ([_queueOfQueues count]) {
// first queue is always running, all others suspended
[(NSOperationQueue *)_queueOfQueues[0] setSuspended:NO];
}
}
}
I might have missed something crucial. The devil's in the details.
This smells a bit like a homework assignment to me. If so, tell me what grade I get. :)
Addendum: Via abhilash1912's comment, a different but similar approach. That code is tested, so it already wins. But it is a bit stale (2 years or so as of today; some deprecated method usage). Moreover, I question whether inheriting from NSOperationQueue is the best path, though it has the virtue of retaining familiarity. Regardless, if you've read this far, it's probably worth looking over.
If you create or find the world's greatest BarrierQueue class, please let us know in the comments or otherwise, so it can be linked up.
Create an NSOperation that is your barrier, then use:
- (void)addDependency:(NSOperation *)operation
To make that barrier operation dependent on all the ones you want to come before it.
I don't think it's possible to create an NSOperation object that's gives you the same sort of functionality, barriers have more to do with the way the queue operates.
The main difference between using a barrier and the dependency mechanism of NSOperations is, in the case of a barrier, the thread queue waits until all running concurrent operations have completed, and then it runs your barrier block, while making sure that any new blocks submitted and any blocks waiting do not run until the critical block has passed.
With an NSOperationQueue, it's impossible to set up the queue in such a way that it'll enforce a proper barrier: all NSOperations added to the queue before your critical NSOperation must be explicitly registered as a dependency with the critical job, and once the critical job has started, you must explicitly guard the NSOperationQueue to make sure no other clients push jobs onto it before the critical job has finished; you guard the queue by adding the critical job as a dependency for the subsequent operations.
(In the case where you know there's only one critical job at a time, this sounds sorta easy, but there will probably be n critical jobs waiting at any one time, which means keeping track of the order jobs are submitted, managing the relative dependency of critical jobs relative to their dependent jobs -- some critical jobs can wait for others, some must be executed in a particular order relative to others... yikes.)
It might be possible to get this level of functionality by setting up an NSOperationQueue with a concurrent job max of one, but that sorta defeats the purpose of doing this, I think. You might also be able to make this work by wrapping an NSOperationQueue in a facade object that protects NSOperations that are submitted "critically."
Just another way... don't hurt me.
Todo: save origin completion and self.maxConcurrentOperationCount = 1 sets queue to serial on adding. But should before execution.
#import "NSOperationQueue+BarrierOperation.h"
#implementation NSOperationQueue (BarrierOperation)
- (void)addOperationAsBarrier:(NSOperation *)op
{
//TODO: needs to save origin completion
// if (op.completionBlock)
// {
// originBlock = op.completionBlock;
// }
NSOperationQueue* qInternal = [NSOperationQueue new];
NSInteger oldMaxConcurrentOperationCount = self.maxConcurrentOperationCount;
op.completionBlock = ^{
self.maxConcurrentOperationCount = oldMaxConcurrentOperationCount;
NSLog(#"addOperationAsBarrier maxConcurrentOperationCount restored");
};
[self addOperationWithBlock:^{
self.maxConcurrentOperationCount = 1;
NSLog(#"addOperationAsBarrier maxConcurrentOperationCount = 1");
}];
[qInternal addOperationWithBlock:^{
NSLog(#"waitUntilAllOperationsAreFinished...");
[self waitUntilAllOperationsAreFinished];
}];
NSLog(#"added OperationAsBarrier");
[self addOperation:op];
}
#end

Waiting for condition to continue

I have a method that I add to a GCD queue that I have created (so it's a serial queue) and then run it async. From within that block of code I make a dispatch to the main queue, when that block of code dispatched to the main queue is complete I set a BOOL flag to YES, so that I further down in my code can check if this condition is YES then I can continue to the next method. Here is the code in short:
dispatch_queue_t queue = dispatch_queue_create("ProcessSerialQueue", 0);
dispatch_async(queue, ^{
Singleton *s = [Singleton sharedInstance];
dispatch_sync(dispatch_get_main_queue(), ^{
[s processWithCompletionBlock:^{
// Process is complete
processComplete = YES;
}];
});
});
while (!processComplete) {
NSLog(#"Waiting");
}
NSLog(#"Ready for next step");
However this does not work, because dispatch_sync is never able to run the code on the main queue. Is this because I'm running a while loop on the main queue (rendering it busy)?
However if I change the implementation of the while loop to this:
while (!processComplete) {
NSLog(#"Waiting")
NSDate *date = [NSDate distantFuture];
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:date];
}
It works without a glitch. Is this an acceptable solution for this scenario? Can I do it any other preferred way? What kind of magic stuff does NSRunLoop do? I need to understand this better.
Part of the main thread's NSRunLoop job is to run any blocks queued on the main thread. By spinning in a while-loop, you're preventing the runloop from progressing, so the queued blocks are never run unless you explicitly make the loop run yourself.
Runloops are a fundemental part of Cocoa, and the documentation is pretty good, so I'd reccommend reading it.
As a rule, I'd avoid manually invoking the runloop as you're doing. You'll waste memory and make make things complicated very quickly if you have multiple manual invocations running on top of one another.
However, there is a much better way of doing this. Split your method into a -process and a -didProcess method. Start the async operation with your -process method, and when it completes, call -didProcess from the completion block. If you need to pass variables from one method to the other, you can pass them as arguments to your -didProcess method.
Eg:
dispatch_queue_t queue = dispatch_queue_create("ProcessSerialQueue", 0);
dispatch_async(queue, ^{
Singleton *s = [Singleton sharedInstance];
dispatch_sync(dispatch_get_main_queue(), ^{
[s processWithCompletionBlock:^{
[self didProcess];
}];
});
});
You might also consider making your singleton own the dispatch queue and make it responsible for handling the dispatch_async stuff, as it'll save on all those nasty embedded blocks if you're always using it asynchronously.
Eg:
[[Singleton sharedInstance] processAyncWithCompletionBlock:^{
NSLog(#"Ready for next step...");
[self didProcess];
}];
Doing something like what you posted will most likely freeze the UI. Rather than freezing up everything, call your "next step" code in a completion block.
Example:
dispatch_queue_t queue = dispatch_queue_create("ProcessSerialQueue", 0);
dispatch_queue_t main = dispatch_get_main_queue();
dispatch_async(queue, ^{
Singleton *s = [Singleton sharedInstance];
dispatch_async(dispatch_get_main_queue(), ^{
[s processWithCompletionBlock:^{
// Next step code
}];
});
});
Don't go creating a loop like that waiting for a value inside a block, variables in blocks are read only, instead call your completion code from inside the block.
dispatch_async(queue, ^{
Singleton *s = [Singelton sharedInstance];
[s processWithCompletionBlock:^{
//process is complete
dispatch_sync(dispatch_get_main_queue(), ^{
//do something on main queue....
NSLog(#"Ready for next step");
});
}];
});
NSLog(#"waiting");

The most common and right pattern for performing synchronous tasks, asynchronous tasks to create a composite operation

I am rather new to iOS and Objective-C.
I am developing a project aiming to make a composition of complex (or "composite") operations as easy as possible: https://github.com/stanislaw/SACompositeOperations
I have four kinds of operations there: two single operations (sync and async) and two complex operations (cascaded and "transactional"). Single operations are used as "atoms" for complex operations, so I want to make them as good as possible in compliance with Objective-C best practices.
What I am interested in is: what code should I choose for these single operations?
By calling the first of two single operations "sync" I mean: run something probably asynchronous with completion handler and lock the flow waiting until it is done. "Async" means truly asynchronous operation - just run operation block in asynchronous fashion.
Here is the single operations code I currently use:
Sync operation
- (void)run:(syncOperationBlock)block {
self.semaphore = dispatch_semaphore_create(0);
block(self);
while (dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_NOW))
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];
}
- (void)finish {
dispatch_semaphore_signal(self.semaphore);
}
#end
Async operation
- (void)run:(asyncOperationBlock)block {
dispatch_queue_t queue = dispatch_queue_create("async_operation.queue", 0);
dispatch_async(queue, ^{
block(self);
});
}
I will be thankful, if someone can suggest any solutions for these single sync- and async- operations: more generic, more common, just better for the cases I've described
Shortly: what is the best code for forced-synchronous operation, for async operation?
Thanks.
My project did evolve significantly since I've asked this question.
From the structural point of view, I can't say much interesting about asynchronous operations: in my project they are all based on dispatch_async and the most valuable functionality is implemented with intensive usage of blocks (mainly: yielding operations themselves to the blocks they execute, allows to control a flow of these operations).
The more interesting thing to note here is the code I currently use for synchronous (or "forced-synchronous") operations - though their usage should be avoided in real apps, they are still applicable in unit tests: one example is a need to straighten the curly asynchronous flow of asynchronous net request to test its result in place, in the context of unit test case.
Though I am posting this as an answer to my non-specific question I would still really like to see any authoritative answer about whether my SASyncOperation is good enough for forced-sync operations (in the sense I've described it in this question) or maybe it could be improved more.
SASyncOperation as it currently written
Does not block main thread if it is run on main thread.
Does not produce excessive CPU polling as simple approaches with while(!completed){}; do.
This is the most important part of the code:
#import "SASyncOperation.h"
#interface SASyncOperation () {
BOOL _isOnMainThread;
dispatch_semaphore_t _semaphore;
}
#end
#implementation SASyncOperation
// …
- (void)start {
_semaphore = dispatch_semaphore_create(0);
_operation(self);
if (_finished) return;
if ((_isOnMainThread = [NSThread isMainThread])) {
while (dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_NOW)) {
CFRunLoopRunInMode(kCFRunLoopDefaultMode, [[NSDate distantFuture] timeIntervalSinceNow], NO);
}
} else {
dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
}
_finished = YES;
}
- (void)run:(^(void)(SASyncOperation *)block {
_operation = [block copy];
[self start];
}
- (void)finish {
_finished = YES;
dispatch_semaphore_signal(_semaphore);
if (_isOnMainThread) {
dispatch_async(dispatch_get_main_queue(), ^{
CFRunLoopStop(CFRunLoopGetMain());
});
}
}
// …
#end
This is how SASyncOperation should be used:
SASyncOperation *syncOperation = [[SASyncOperation alloc] init];
[syncOperation run:^(SASyncOperation *so) {
doSomeThingMultiQueuedPossiblyMultiblockedAndAsynchronous(^{
soOver = YES;
[so finish];
});
}]; // <- (*)
// (*) The flow will be stopped at this point waiting when 'so' operation will finish itself

Central Grand Dispatcher: Run the same method in different queues/blocks

Why does my code crashes?
dispatch_async(queue_A, ^{
#synchronized(self) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self logInfo:#"queue_A"];
[pool release];
}
});
dispatch_async(queue_B, ^{
#synchronized(self) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self logInfo:#"queue_B"];
[pool release];
}
});
You're better off avoiding using #syncronized inside dispatch_async, as suggested in the comments. If it's not safe to call [self logInfo:...] then you might want to either:
Use a dispatch group to make sure multiple dispatch_async() calls to a resource don't crash your app. Mike Ash has a good write-up of this technique. Check out his examples.
Use a dispatch semaphore to force separate calls to wait for each other to complete. See the manpage for more.
I'm not sure what logInfo does in this context so you may be able to rewrite that as well.
Solved the problem.
Access to UI has to be via main queue ONLY