I have a serial dispatch queue created with:
dispatch_queue_t serialQueue = dispatch_queue_create("com.unique.name.queue", DISPATCH_QUEUE_SERIAL);
I want to use this serial queue to ensure thread safety for class access, while automatically doing work asynchronously that doesn't need to return to the calling thread.
- (void)addObjectToQueue:(id)object
{
dispatch_async(serialQueue, ^{
// process object and add to queue
});
}
- (BOOL)isObjectInQueue:(id)object
{
__block BOOL returnValue = NO;
dispatch_sync(serialQueue, ^{
// work out return value
});
return returnValue;
}
If I call the addObjectToQueue: method, then immediately call the isObjectInQueue: method, are they guaranteed to be executed in the same order, or will/could the isObjectInQueue execute first?
In other words, does dispatch_async perform exactly the same as dispatch_sync (scheduling the block immediately) except that it doesn't block the calling thread?
I have seen similar questions with answers going both ways, so I am looking for a definitive answer, preferably backed with Apple documentation.
Are they guaranteed to be executed in the same order?
Yes.
Will / could the isObjectInQueue execute first?
Yes.
The reason for the yes to both answers is you should consider threading. Which is presumably why you are using the serial queue in the first place. You are making access to that queue thread safe.
Basically, the blocks will execute in the order in which they are put on the serial queue. That is 100% guaranteed. However, if multiple threads are hammering away at this then one thread may get in first to read something from the queue before another has had chance to add it.
In other words, does dispatch_async perform exactly the same as dispatch_sync (scheduling the block immediately) except that it doesn't block the calling thread?
That's right. In both cases the block is added to the queue. It is added immediately. dispatch_sync just waits for the block to finish before returning whereas dispatch_async returns immediately.
I guess your question is, will the main thread keep running while dispatch_async is still executing the queue operation? I assume it won't, because that would deserve a explicit mention. If anything, I found this in dispatch_async.3 which suggests this is the case:
Conceptually, dispatch_sync() is a convenient wrapper around
dispatch_async() with the addition of a semaphore to wait for
completion of the block, and a wrapper around the block to signal its
completion.
And indeed, if you follow the source code for dispatch_async in queue.c you'll see that the block is queued on the foreground, and only after that, execution returns to the code that called dispatch_async. Therefore if the queue is serial, dispatch_async followed by a dispatch_sync from the same thread will queue the blocks in order.
Because dispatch_sync will block until the block (and all blocks before in a serial queue) are done executing, then your code would be right. isObjectInQueue: will correctly report if the object added before is in the queue.
edit: on a multithreaded environment I would write the code above as:
- (void)addObjectToQueue:(id)object
{
dispatch_barrier_async(_queue, ^{
// process object and add to queue
});
}
- (BOOL)isObjectInQueue:(id)object
{
__block BOOL returnValue = NO;
dispatch_sync(_queue, ^{
// work out return value
});
return returnValue;
}
because execution of each method can be deferred at any point in favor of another thread.
Related
I'm trying to make a network call run in a background thread so it doesn't freeze my app while it's waiting.
The call happens when I do:
nextTime = [myObj getNextTime];
I do an NSLog as soon as I get it, and that one works.
However, when I'm outside of the dispatch block, the same
NSLog prints out null.
myObj *current = ((myObj *)sortedArray[i]);
__block NSString *nextTime;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^{
nextTime = [myObj getNextTime];
NSLog(#"inside%#",nextTime);
dispatch_sync(dispatch_get_main_queue(), ^{
});
});
NSLog(#"outside%#",nextTime);
Any ideas why the outer log is printing null? Am I doing something horribly wrong and I just missed it? Thanks!
That's because you're setting it inside an asynchronous block, and asynchronous blocks return immediately. If you look at the time stamps of the two logs, you'll see that the outer log is actually being posted before both the inner log, and the setting of the variable.
From the GCD docs on dispatch_async():
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.
Your "outside" NSLog statement should actually go in that inner dispatch_async block that is set to run on the main thread, because that block will execute after you've set the value of nextTime. Any code you place below your asynchronous block call will likely execute way before the code inside the block.
What happens if you dispatch_async a block of code on a queue that's currently blocked by it's own dispatch_sync operation? Do they lock or will the blocked queue continue after the dispatch_sync operation returns?
I have an object I created that manages access to a backing store (SQLite, in this case). It uses one concurrent GCD queue and any other objects that want to access the information from the store will pass a request to the manager along with a block that will be executed asynchronously. The essence of what happens is this (not actual code):
- (void) executeRequest:(StoreRequest *)request withCompletionBlock:(void(^)(NSInteger result)block{
dispatch_queue_t currentContext = dispatch_get_current_queue();
dispatch_async(_storeQueue, ^{
NSInteger result = [_store executeRequest:request];
if (block){
dispatch_async(currentContext, ^{
block(result);
}
}
});
}
The real code is a bit more complex (I actually queue up and store requests/blocks/contexts to execute at the end of a run loop). I also use dispatch_barrier_async for write requests to prevent concurrent read/writing. This all works fine, but in certain situations I also need to perform a synchronous request on the store. Now this request doesn't need to be performed before any queued up operations, but I do need the requesting queue blocked until the operation is performed. This can be easily done:
- (NSInteger) executeRequest:(StoreRequest *)request{
__block NSInteger result = 0;
dispatch_sync(_storeQueue, ^{
result = [_store executeRequest:request];
});
return result;
}
My question is this: What happens if a pending asynchronous operation placed before the synchronous operation dispatches a block of code asynchronously on the queue that is currently blocked by the synchronous dispatch. In other words, the above operation will dispatch its request at the end of the _store queue and wait. But it's quite possible (even likely) that the operations in front of it include asynchronous dispatches back to the waiting queue (for other operations). Will this lock the threads? Since the queued blocks are dispatched asynchronously the _store queue will never be blocked and therefore will finish, theoretically allowing the queue it's blocking to continue...but I'm not sure what happens with the blocks that were asynchronously dispatched or if dispatching anything to a block thread locks it up. I would assume that the blocked queue will continue, finish it's request and then the process the pending blocks, but I want to make sure.
Actually, now that I've written this all up, I'm pretty sure it'll work just fine, but I'm going to post this question anyway to make sure I'm not missing anything.
dispatch_async never blocks. It's that simple.
The dispatch_async itself never blocks. It appends the block to the end of the queue and returns immediately.
Will the block get executed? It depends. In a sequential queue, if one block is blocked, no other block will execute until that block gets unblocked and finishes. On a background queue, the queue can use multiple threads, so even if some blocks are blocked, it will just start other blocks. I haven't tried if there is a limit to the number of blocked blocks, but there's a good chance that all unblocked blocks will eventually execute and finish, and you are left with the blocked ones.
Are Objective-C blocks always executed in a separate thread?
Specifically, I'm asking about the sendAsynchronousRequest:queue:completionHandler method of the NSURLConnection class. This is the scenario:
Main thread (1st thread) calls the sendAsynchronousRequest method the
sendAsynchronousRequest is executed on a 2nd thread, managed by the
NSOperationQueue when method is completed and calls
commpletionHandler, which thread is it executed on? 2nd thread? yet
another 3rd thread? or the 1st thread?
Thanks!
It executes it on whatever operation queue you specify as the queue argument:
Loads the data for a URL request and executes a handler block on an operation queue when the request completes or fails.
The queue parameter is documented as:
The operation queue to which the handler block is dispatched when the request completes or failed.
So it's really up to the NSOperationQueue exactly how many threads are used. I'd expect pooling behaviour - so while there can be multiple threads, I wouldn't expect a different thread per handler, necessarily.
A block is just a closure, like you have them in python or functional languages. They don't "run on a thread" they run where they are called.
int main(void)
{
void (^f)(void) { printf("hello world!\n"); }
f();
return 0;
}
Does just what you think it does, no dispatch queues, no threads, no nothing.
Though, once you have blocks with all their nice capture semantics, it's very tempting to have APIs to schedule their execution everywhere. But basically, a block, is just the same as a function pointer and an ad-hoc struct containing all the variable captured, passed as an argument to the callback (it's even how it's implemented in the compiler).
As others have said, it will run on whatever queue you have specified. If this is a background queue, and you want to execute some code on the main thread, you can iclude a GCD block accessing the main queue. Your completion block would look something like this:
^(NSURLResponse *response, NSData *data, NSError*error){
// do whatever in the background
dispatch_async(dispatch_get_main_queue(), ^{
// this block will run on the main thread
});
}
Blocks are executed wherever they are told. Wrapping code in a block does not affect the thread or queue it will be run on. In your particular case, as documented, the completion block is executed on the queue that is passed in in the queue parameter.
I'm not sure, for your purposes, if you really need to distinguish between a queue and a thread, the key principle is that the URL request is performed asynchronously to the calling code, and the completion block is performed on the queue passed in as the method parameter.
I ran into a scenario where I had a delegate callback which could occur on either the main thread or another thread, and I wouldn't know which until runtime (using StoreKit.framework).
I also had UI code that I needed to update in that callback which needed to happen before the function executed, so my initial thought was to have a function like this:
-(void) someDelegateCallback:(id) sender
{
dispatch_sync(dispatch_get_main_queue(), ^{
// ui update code here
});
// code here that depends upon the UI getting updated
}
That works great, when it is executed on the background thread. However, when executed on the main thread, the program comes to a deadlock.
That alone seems interesting to me, if I read the docs for dispatch_sync right, then I would expect it to just execute the block outright, not worrying about scheduling it into the runloop, as said here:
As an optimization, this function invokes the block on the current thread when possible.
But, that's not too big of a deal, it simply means a bit more typing, which lead me to this approach:
-(void) someDelegateCallBack:(id) sender
{
dispatch_block_t onMain = ^{
// update UI code here
};
if (dispatch_get_current_queue() == dispatch_get_main_queue())
onMain();
else
dispatch_sync(dispatch_get_main_queue(), onMain);
}
However, this seems a bit backwards. Was this a bug in the making of GCD, or is there something that I am missing in the docs?
dispatch_sync does two things:
queue a block
blocks the current thread until the block has finished running
Given that the main thread is a serial queue (which means it uses only one thread), if you run the following statement on the main queue:
dispatch_sync(dispatch_get_main_queue(), ^(){/*...*/});
the following events will happen:
dispatch_sync queues the block in the main queue.
dispatch_sync blocks the thread of the main queue until the block finishes executing.
dispatch_sync waits forever because the thread where the block is supposed to run is blocked.
The key to understanding this issue is that dispatch_sync does not execute blocks, it only queues them. Execution will happen on a future iteration of the run loop.
The following approach:
if (queueA == dispatch_get_current_queue()){
block();
} else {
dispatch_sync(queueA, block);
}
is perfectly fine, but be aware that it won't protect you from complex scenarios involving a hierarchy of queues. In such case, the current queue may be different than a previously blocked queue where you are trying to send your block. Example:
dispatch_sync(queueA, ^{
dispatch_sync(queueB, ^{
// dispatch_get_current_queue() is B, but A is blocked,
// so a dispatch_sync(A,b) will deadlock.
dispatch_sync(queueA, ^{
// some task
});
});
});
For complex cases, read/write key-value data in the dispatch queue:
dispatch_queue_t workerQ = dispatch_queue_create("com.meh.sometask", NULL);
dispatch_queue_t funnelQ = dispatch_queue_create("com.meh.funnel", NULL);
dispatch_set_target_queue(workerQ,funnelQ);
static int kKey;
// saves string "funnel" in funnelQ
CFStringRef tag = CFSTR("funnel");
dispatch_queue_set_specific(funnelQ,
&kKey,
(void*)tag,
(dispatch_function_t)CFRelease);
dispatch_sync(workerQ, ^{
// is funnelQ in the hierarchy of workerQ?
CFStringRef tag = dispatch_get_specific(&kKey);
if (tag){
dispatch_sync(funnelQ, ^{
// some task
});
} else {
// some task
}
});
Explanation:
I create a workerQ queue that points to a funnelQ queue. In real code this is useful if you have several “worker” queues and you want to resume/suspend all at once (which is achieved by resuming/updating their target funnelQ queue).
I may funnel my worker queues at any point in time, so to know if they are funneled or not, I tag funnelQ with the word "funnel".
Down the road I dispatch_sync something to workerQ, and for whatever reason I want to dispatch_sync to funnelQ, but avoiding a dispatch_sync to the current queue, so I check for the tag and act accordingly. Because the get walks up the hierarchy, the value won't be found in workerQ but it will be found in funnelQ. This is a way of finding out if any queue in the hierarchy is the one where we stored the value. And therefore, to prevent a dispatch_sync to the current queue.
If you are wondering about the functions that read/write context data, there are three:
dispatch_queue_set_specific: Write to a queue.
dispatch_queue_get_specific: Read from a queue.
dispatch_get_specific: Convenience function to read from the current queue.
The key is compared by pointer, and never dereferenced. The last parameter in the setter is a destructor to release the key.
If you are wondering about “pointing one queue to another”, it means exactly that. For example, I can point a queue A to the main queue, and it will cause all blocks in the queue A to run in the main queue (usually this is done for UI updates).
I found this in the documentation (last chapter):
Do not call the dispatch_sync function from a task that is executing
on the same queue that you pass to your function call. Doing so will
deadlock the queue. If you need to dispatch to the current queue, do
so asynchronously using the dispatch_async function.
Also, I followed the link that you provided and in the description of dispatch_sync I read this:
Calling this function and targeting the current queue results in deadlock.
So I don't think it's a problem with GCD, I think the only sensible approach is the one you invented after discovering the problem.
I know where your confusion comes from:
As an optimization, this function invokes the block on the current
thread when possible.
Careful, it says current thread.
Thread != Queue
A queue doesn't own a thread and a thread is not bound to a queue. There are threads and there are queues. Whenever a queue wants to run a block, it needs a thread but that won't always be the same thread. It just needs any thread for it (this may be a different one each time) and when it's done running blocks (for the moment), the same thread can now be used by a different queue.
The optimization this sentence talks about is about threads, not about queues. E.g. consider you have two serial queues, QueueA and QueueB and now you do the following:
dispatch_async(QueueA, ^{
someFunctionA(...);
dispatch_sync(QueueB, ^{
someFunctionB(...);
});
});
When QueueA runs the block, it will temporarily own a thread, any thread. someFunctionA(...) will execute on that thread. Now while doing the synchronous dispatch, QueueA cannot do anything else, it has to wait for the dispatch to finish. QueueB on the other hand, will also need a thread to run its block and execute someFunctionB(...). So either QueueA temporarily suspends its thread and QueueB uses some other thread to run the block or QueueA hands its thread over to QueueB (after all it won't need it anyway until the synchronous dispatch has finished) and QueueB directly uses the current thread of QueueA.
Needless to say that the last option is much faster as no thread switch is required. And this is the optimization the sentence talks about. So a dispatch_sync() to a different queue may not always cause a thread switch (different queue, maybe same thread).
But a dispatch_sync() still cannot happen to the same queue (same thread, yes, same queue, no). That's because a queue will execute block after block and when it currently executes a block, it won't execute another one until the currently executed is done. So it executes BlockA and BlockA does a dispatch_sync() of BlockB on the same queue. The queue won't run BlockB as long as it still runs BlockA, but running BlockA won't continue until BlockB has ran. See the problem? It's a classical deadlock.
The documentation clearly states that passing the current queue will cause a deadlock.
Now they don’t say why they designed things that way (except that it would actually take extra code to make it work), but I suspect the reason for doing things this way is because in this special case, blocks would be “jumping” the queue, i.e. in normal cases your block ends up running after all the other blocks on the queue have run but in this case it would run before.
This problem arises when you are trying to use GCD as a mutual exclusion mechanism, and this particular case is equivalent to using a recursive mutex. I don’t want to get into the argument about whether it’s better to use GCD or a traditional mutual exclusion API such as pthreads mutexes, or even whether it’s a good idea to use recursive mutexes; I’ll let others argue about that, but there is certainly a demand for this, particularly when it’s the main queue that you’re dealing with.
Personally, I think that dispatch_sync would be more useful if it supported this or if there was another function that provided the alternate behaviour. I would urge others that think so to file a bug report with Apple (as I have done, ID: 12668073).
You can write your own function to do the same, but it’s a bit of a hack:
// Like dispatch_sync but works on current queue
static inline void dispatch_synchronized (dispatch_queue_t queue,
dispatch_block_t block)
{
dispatch_queue_set_specific (queue, queue, (void *)1, NULL);
if (dispatch_get_specific (queue))
block ();
else
dispatch_sync (queue, block);
}
N.B. Previously, I had an example that used dispatch_get_current_queue() but that has now been deprecated.
Both dispatch_async and dispatch_sync perform push their action onto the desired queue. The action does not happen immediately; it happens on some future iteration of the run loop of the queue. The difference between dispatch_async and dispatch_sync is that dispatch_sync blocks the current queue until the action finishes.
Think about what happens when you execute something asynchronously on the current queue. Again, it does not happen immediately; it puts it in a FIFO queue, and it has to wait until after the current iteration of the run loop is done (and possibly also wait for other actions that were in the queue before you put this new action on).
Now you might ask, when performing an action on the current queue asynchronously, why not always just call the function directly, instead of wait until some future time. The answer is that there is a big difference between the two. A lot of times, you need to perform an action, but it needs to be performed after whatever side effects are performed by functions up the stack in the current iteration of the run loop; or you need to perform your action after some animation action that is already scheduled on the run loop, etc. That's why a lot of times you will see the code [obj performSelector:selector withObject:foo afterDelay:0] (yes, it's different from [obj performSelector:selector withObject:foo]).
As we said before, dispatch_sync is the same as dispatch_async, except that it blocks until the action is completed. So it's obvious why it would deadlock -- the block cannot execute until at least after the current iteration of the run loop is finished; but we are waiting for it to finish before continuing.
In theory it would be possible to make a special case for dispatch_sync for when it is the current thread, to execute it immediately. (Such a special case exists for performSelector:onThread:withObject:waitUntilDone:, when the thread is the current thread and waitUntilDone: is YES, it executes it immediately.) However, I guess Apple decided that it was better to have consistent behavior here regardless of queue.
Found from the following documentation.
https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/index.html#//apple_ref/c/func/dispatch_sync
Unlike dispatch_async, "dispatch_sync" function does not return until the block has finished. Calling this function and targeting the current queue results in deadlock.
Unlike with dispatch_async, no retain is performed on the target queue. Because calls to this function are synchronous, it "borrows" the reference of the caller. Moreover, no Block_copy is performed on the block.
As an optimization, this function invokes the block on the current thread when possible.
Working with some code, I'm coming across run loops, which I'm new to, inside NSOperations.
The NSOperations are busy downloading data - and whilst they are busy, there is code to wait for the downloads to complete, in the form of NSRunLoops and thread sleeping.
This code in particular is of interest to me:
while (aCertainConditionIsTrue && [self isCancelled]==NO) {
if(![[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]){
[NSThread sleepForTimeInterval:1.0];
}
}
I've read about the run loops, and runMode:beforeDate: will wait for an input source or a timeout. Although I'm not 100% what counts as an input souce.
On the first execution of this it always returns NO and hits the sleepForTimeInterval:. Is this bad?
In a particular utility class, it's hitting the sleepForTimeInterval: a lot - once for each thread - which significantly hurts the performance.
Any better solutions for this, or advice?
Sleeping locks up the thread. Perhaps you change your code to use performSelector:withObject:afterDelay. That way your thread can continue to run.
...
done = NO;
[self checkDoneCondition:nil];
...
- (void)checkDoneCondition:(id)object {
if (aCertainConditionIsTrue && [self isCancelled]==NO) {
if(...) {
[self performSelector:#selector(checkDoneCondition:) withObject:[con error] afterDelay:1.0];
} else {
done = YES;
}
}
}
It looks like you need to use a concurrent NSOperation. Here is the relevant part in the Apple docs:
In contrast to a non-concurrent operation, which runs synchronously, a
concurrent operation runs asynchronously. In other words, when you
call the start method of a concurrent operation, that method could
return before the corresponding task is completed. This might happen
because the operation object created a new thread to execute the task
or because the operation called an asynchronous function. It does not
actually matter if the operation is ongoing when control returns to
the caller, only that it could be ongoing.
(...)
In a concurrent operation, your start method is responsible for
starting the operation in an asynchronous manner. Whether you spawn a
thread or call an asynchronous function, you do it from this method.
Upon starting the operation, your start method should also update the
execution state of the operation as reported by the isExecuting
method. You do this by sending out KVO notifications for the
isExecuting key path, which lets interested clients know that the
operation is now running. Your isExecuting method must also return the
status in a thread-safe manner.
(from https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/NSOperation_class/Reference/Reference.html)
In other words, you can override the -start method in your NSOperation subclass, and have ivar for the executing and finished property. This method will start the download in a separate thread. When the download starts, you set the executing flag and trigger KVO. WHen it is finished in this thread, you do the same with finished and executing. It seems complicated but it's actually quite simple.
See also this question on Stack Overflow with a great explanation: Subclassing NSOperation to be concurrent and cancellable