NSOperationQueue concurrent operations with new threads starting inside operations - iphone

I have just started using NSOperation/NSOprationQueue, so forgive me for asking this question. :P
At the start of my app, I want some set of functions to be performed in a queue, so that when one ends, another starts (I have set setMaxConcurrentOperationCount to 1 so that only one operation occurs at a time). All should happen in background, as its a kind of a download/upload to server of information.
I put the first operation in the queue, that calls another method, which may invoke some new threads to perform some other actions.
My question is,
Will the Operation Queue wait for all the methods/threads started in the first operation to complete before starting second operation?

There are two kinds of NSOperations, concurrent and non-concurrent.
The non-concurrent operations are implemented in their -main method, and when this method returns, the operation is considered done. If you spawn a thread inside -main and want the operation to run until the thread is finished, you should block the execution in -main until the thread is done (using a semaphore, for example).
The concurrent operations have a set of predicates like -isExecuting and -isFinished, and there’s a -start method that starts the operation. This method may just spawn some background processing and return immediately, the whole operation is not considered finished until -isFinished says so.
Now that we have GCD it’s usually a good idea to consider blocks and dispatch queues as a lighter alternative to NSOperation, also see the –addOperationWithBlock: method on NSOperationQueue.

If NSOperation is doing asynchronous task like something like [NSURLConnection sendAsynchronousRequest:.....] than the thread on which operation is running wont wait for response, and it will not wait. As soon main method last statement or block last statement is executed operation would be remove from queue and next operation would start.

You can use something like this
NSOperationQueue *queue=[NSOperationQueue new];
[queue setMaxConcurrentOperationCount:1];
NSBlockOperation *blockOperation1 = [NSBlockOperation blockOperationWithBlock:^{
//operation first
}];
NSBlockOperation *blockOperation2 = [NSBlockOperation blockOperationWithBlock:^{
//operation second
}];
[blockOperation2 addDependency:blockOperation1];
[queue addOperation:blockOperation1];
[queue addOperation:blockOperation2];

Related

sendAsynchronousRequest NSURLConnectionRequest

In the method below, if I do data processing in the completionHandler, is this going to block the main thread or not? In other words is whatever performed in the completionHandler done on the main thread or is it done on the background thread?
+ (void)sendAsynchronousRequest:(NSURLRequest *)request
queue:(NSOperationQueue*) queue
completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*)) handler NS_AVAILABLE(10_7, 5_0);
Per the documentation, queue is:
The operation queue to which the handler block is dispatched when the request completes or failed.
So handler will be performed there. Notably no promises are made either way as to where the actual URL connection stuff will be done, so if you want to finish on the main thread you should just specify [NSOperationQueue mainQueue].
It depends on the OS version you are supporting. According to the documentation, the completion handler block is executed on a NSOperationQueue.
+(void)sendAsynchronousRequest:(NSURLRequest *)request
queue:(NSOperationQueue*) queue
completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*)) handler NS_AVAILABLE(10_7, 5_0);
Several lines down into the NSOperationQueue documentation, you will see this quote:
Operation queues usually provide the threads used to run their operations. In OS X v10.6 and later, operation queues use the libdispatch library (also known as Grand Central Dispatch) to initiate the execution of their operations. As a result, operations are always executed on a separate thread, regardless of whether they are designated as concurrent or non-concurrent operations. In OS X v10.5, however, operations are executed on separate threads only if their isConcurrent method returns NO. If that method returns YES, the operation object is expected to create its own thread (or start some asynchronous operation); the queue does not provide a thread for it.
Note: In iOS 4 and later, operation queues use Grand Central Dispatch to execute operations. Prior to iOS 4, they create separate threads for non-concurrent operations and launch concurrent operations from the current thread. For a discussion of the difference between concurrent and non-concurrent operations and how they are executed, see NSOperation Class Reference.
If your app is supporting OSX v10.6 and above, then the completion handler should be executed on a separate thread. In OS X v10.5, you will have to specify it. For iOS it's also using GCD so operations are also executed on separate threads from iOS 4 and upwards. Hope that was clearer than Tommy's response.

NSManagedObjectContext performBlockAndWait: doesn't execute on background thread?

I have an NSManagedObjectContext declared like so:
- (NSManagedObjectContext *) backgroundMOC {
if (backgroundMOC != nil) {
return backgroundMOC;
}
backgroundMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
return backgroundMOC;
}
Notice that it is declared with a private queue concurrency type, so its tasks should be run on a background thread. I have the following code:
-(void)testThreading
{
/* ok */
[self.backgroundMOC performBlock:^{
assert(![NSThread isMainThread]);
}];
/* CRASH */
[self.backgroundMOC performBlockAndWait:^{
assert(![NSThread isMainThread]);
}];
}
Why does calling performBlockAndWait execute the task on the main thread rather than background thread?
Tossing in another answer, to try an explain why performBlockAndWait will always run in the calling thread.
performBlock is completely asynchronous. It will always enqueue the block onto the queue of the receiving MOC, and then return immediately. Thus,
[moc performBlock:^{
// Foo
}];
[moc performBlock:^{
// Bar
}];
will place two blocks on the queue for moc. They will always execute asynchronously. Some unknown thread will pull blocks off of the queue and execute them. In addition, those blocks are wrapped within their own autorelease pool, and also they will represent a complete Core Data user event (processPendingChanges).
performBlockAndWait does NOT use the internal queue. It is a synchronous operation that executes in the context of the calling thread. Of course, it will wait until the current operations on the queue have been executed, and then that block will execute in the calling thread. This is documented (and reasserted in several WWDC presentations).
Furthermore, performBockAndWait is re-entrant, so nested calls all happen right in that calling thread.
The Core Data engineers have been very clear that the actual thread in which a queue-based MOC operation runs is not important. It's the synchronization by using the performBlock* API that's key.
So, consider 'performBlock' as "This block is being placed on a queue, to be executed at some undetermined time, in some undetermined thread. The function will return to the caller as soon as it has been enqueued"
performBlockAndWait is "This block will be executed at some undetermined time, in this exact same thread. The function will return after this code has completely executed (which will occur after the current queue associated with this MOC has drained)."
EDIT
Are you sure of "performBlockAndWait does NOT use the internal queue"?
I think it does. The only difference is that performBlockAndWait will
wait until the block's completion. And what do you mean by calling
thread? In my understanding, [moc performBlockAndWait] and [moc
performBloc] both run on its private queue (background or main). The
important concept here is moc owns the queue, not the other way
around. Please correct me if I am wrong. – Philip007
It is unfortunate that I phrased the answer as I did, because, taken by itself, it is incorrect. However, in the context of the original question it is correct. Specifically, when calling performBlockAndWait on a private queue, the block will execute on the thread that called the function - it will not be put on the queue and executed on the "private thread."
Now, before I even get into the details, I want to stress that depending on internal workings of libraries is very dangerous. All you should really care about is that you can never expect a specific thread to execute a block, except anything tied to the main thread. Thus, expecting a performBlockAndWait to not execute on the main thread is not advised because it will execute on the thread that called it.
performBlockAndWait uses GCD, but it also has its own layer (e.g., to prevent deadlocks). If you look at the GCD code (which is open source), you can see how synchronous calls work - and in general they synchronize with the queue and invoke the block on the thread that called the function - unless the queue is the main queue or a global queue. Also, in the WWDC talks, the Core Data engineers stress the point that performBlockAndWait will run in the calling thread.
So, when I say it does not use the internal queue, that does not mean it does not use the data structures at all. It must synchronize the call with the blocks already on the queue, and those submitted in other threads and other asynchronous calls. However, when calling performBlockAndWait it does not put the block on the queue... instead it synchronizes access and runs the submitted block on the thread that called the function.
Now, SO is not a good forum for this, because it's a bit more complex than that, especially w.r.t the main queue, and GCD global queues - but the latter is not important for Core Data.
The main point is that when you call any performBlock* or GCD function, you should not expect it to run on any particular thread (except something tied to the main thread) because queues are not threads, and only the main queue will run blocks on a specific thread.
When calling the core data performBlockAndWait the block will execute in the calling thread (but will be appropriately synchronized with everything submitted to the queue).
I hope that makes sense, though it probably just caused more confusion.
EDIT
Furthermore, you can see the unspoken implications of this, in that the way in which performBlockAndWait provides re-entrant support breaks the FIFO ordering of blocks. As an example...
[context performBlockAndWait:^{
NSLog(#"One");
[context performBlock:^{
NSLog(#"Two");
}];
[context performBlockAndWait:^{
NSLog(#"Three");
}];
}];
Note that strict adherence to the FIFO guarantee of the queue would mean that the nested performBlockAndWait ("Three") would run after the asynchronous block ("Two") since it was submitted after the async block was submitted. However, that is not what happens, as it would be impossible... for the same reason a deadlock ensues with nested dispatch_sync calls. Just something to be aware of if using the synchronous version.
In general, avoid sync versions whenever possible because dispatch_sync can cause a deadlock, and any re-entrant version, like performBlockAndWait will have to make some "bad" decision to support it... like having sync versions "jump" the queue.
Why not? Grand Central Dispatch's block concurrency paradigm (which I assume MOC uses internally) is designed so that only the runtime and operating system need to worry about threads, not the developer (because the OS can do it better than you can do to having more detailed information). Too many people assume that queues are the same as threads. They are not.
Queued blocks are not required to run on any given thread (the exception being blocks in the main queue must execute on the main thread). So, in fact, sometimes sync (i.e. performBlockAndWait) queued blocks will run on the main thread if the runtime feels it would be more efficient than creating a thread for it. Since you are waiting for the result anyway, it wouldn't change the way your program functioned if the main thread were to hang for the duration of the operation.
This last part I am not sure if I remember correctly, but in the WWDC 2011 videos about GCD, I believe that it was mentioned that the runtime will make an effort to run on the main thread, if possible, for sync operations because it is more efficient. In the end though, I suppose the answer to "why" can only be answered by the people who designed the system.
I don't think that the MOC is obligated to use a background thread; it's just obligated to ensure that your code will not run into concurrency issues with the MOC if you use performBlock: or performBlockAndWait:. Since performBlockAndWait: is supposed to block the current thread, it seems reasonable to run that block on that thread.
The performBlockAndWait: call only makes sure that you execute the code in such a way that you don't introduce concurrency (i.e. on 2 threads performBlockAndWait: will not run at the same time, they will block each other).
The long and the short of it is that you can't depend on which thread a MOC operation runs on, well basically ever. I've learned the hard way that if you use GCD or just straight up threads, you always have to create local MOCs for each operation and then merge them to the master MOC.
There is a great library (MagicalRecord) that makes that process very simple.

NSOperation cancelAllOperations takes too long to cancel operations

I have an NSOperationQueue to which i have added my custom class's objects(inherits from NSOperation) i have set the "setMaxConcurrentOperationCount" to be 1. But when i cancel all the operations like this:
[mOperationQueue cancelAllOperations];
it takes about 10 -15 seconds sometimes to cancel them all.
NSOperationQueue contains about 60-80 tasks(Operations).
Initially i was canceling the operations in main thread which obviously blocked the main thread but now i have done that in a different thread.But my main issue is that it takes too long.
Any Suggestions ?
Your operation should check to see if it's been cancelled more often (e.g. in its implementation of -main).
Beyond that, run a sampler to see what is taking all that time.

Cancel NSOperation

I am using the following code in a loop:
-(void)getUpdatedComments
{
if(checkComments)
{
objParseOperation=[[ParseOperation alloc] initWithUDID:[[NSUserDefaults standardUserDefaults] valueForKey:kDeviceUDID]:self];
[operationQueue addOperation:objParseOperation3];
}
}
where operationQueue is an object of type NSOperationQueue. I am calling this method every few seconds.
If I call this method after the first time, do I need to cancel the previous operation or just do [objParseOperation release]?
If you are going to use the same queue for adding more new operations then there isn't much use in releasing it and creating a new one. Simply canceling all operations and then adding more operations is enough. You can do so by calling cancelAllOperations on the queue. Note that operations that are already running will continue to run unless they check for the cancellation.
This method sends a cancel message to all operations currently in the queue. Queued operations are cancelled before they begin executing. If an operation is already executing, it is up to that operation to recognize the cancellation and stop what it is doing.
Wether or not releasing the queue will immediately release the enqueued operations or not is not documented and hence should be considered as undefined behavior. Therefor you shouldn't assume that it will work either way and you should not rely on it (see dangerous to autorelease NSOperationQueue).
There are however evidence that suggests that operations will retain their queue such as that GCD queues are retained by the system while they have asynchronous blocks running/pending. You can read in the Grand Central Dispatch documentation that "the queue is retaind by the system until the block has run to completion". Still, the documentation doesn't specify the behavior for NSOperationQueues like mentioned above.
dispatch_async
Submits a block for asynchronous execution on a dispatch queue and returns immediately.
void dispatch_async(
dispatch_queue_t queue,
dispatch_block_t block);
Parameters
queue
The queue on which to submit the block. The queue is retained by the system until the block has run to completion. This parameter cannot be NULL.
block
The block to submit to the target dispatch queue. This function performs Block_copy and Block_release on behalf of callers. This parameter cannot be NULL.
Discussion
This function is the fundamental mechanism for submitting blocks to a dispatch queue. Calls to this function always return immediately after the block has been submitted and never wait for the block to be invoked. The target queue determines whether the block is invoked serially or concurrently with respect to other blocks submitted to that same queue. Independent serial queues are processed concurrently with respect to each other.

scheduling async downloads in main thread's runloop vs bg thread's runloop on iOS?

Here's a slide from WWDC 2010 session 208:
conn = [[NSURLConnection alloc] initWithRequest:req
delegate:self startImmediately:NO];
[conn scheduleInRunLoop: [NSRunLoop currentRunLoop]
forMode: NSDefaultRunLoopMode];
[conn start];
Are there any problems associated with putting multiple conn's in the currentRunLoop?
What benefits does scheduling the NSURLConnection in a background thread's runloop?
Thank you!
Your use of the phrase "secondary runloop" suggests that you don't know what a run loop is.
An NSRunLoop is an implementation of a thread's "main loop". More or less,
while ([runLoop waitNextEvent]) {
NSAutoreleasePool * pool = [NSAutoreleasePool new];
[runLoop handleEvent];
[pool release]; pool = nil;
}
A run loop has a thread. Each thread has at most one run loop. "performSelectorOnMainThread" schedules it on the run loop, but programmers generally talk about threads rather than whatever run loop abstraction it's using, since they're all the same. Not all threads have run loops (NSThread's functions will generally give you a thread with no run loop; I think you have to create the run loop yourself if you want one).
"currentRunLoop" is the run loop of the currently executing thread. This is probably the main thread, unless you've used NSOperation/dispatch_*/etc. If you schedule it on another thread, then (I think) the delegate callbacks get run from another thread. You probably don't want that to happen.
Now, threads.
There is little point spawning a background thread which is idle most of the time. NSURLConnection should to very little processing (you can't get that much bandwidth into a phone in the first place); there's practically no overhead associated with running it in the main run loop; threads tend to have much larger overheads.
If you're processing the data, and the processing is CPU-intensive, you might want it running in the background thread. You might put the connections in the background thread, but in general it's easier to do as much as possible in the main thread.
And I won't get started on inter-thread communication woes, because they're a major pain. Only use concurrency if you know you need it.
(And until the iPhone goes dual-core, you almost certainly don't need it for 99% of the code you write.)