2

Let's say I have the following code:

dispatch_async(dispatch_get_main_queue()) {
    myFunction()
}

This says to call the block, which calls myFunction, asynchronously. Let's say that I call this code in my main queue, which is also the queue specified for the dispatch_async call.

When does this block actually get called in this case? Does my current queue get pre-empted and the block run immediately, or does the current call stack unroll and the block gets called at the next event loop? Or something else?

  • By definition of async, the order of execution is indeterminate - the OS will decide whether to pre-empt or not. So you should not base your code on a specific expected outcome. – kfmfe04 Oct 19 '15 at 00:11
  • @kfmfe04 That is not true. The main queue is a serial queue which means that a second task cannot be executed concurrently. Presumably, the code that calls dispatch_async is a task currently executing on the main queue, and that task must complete before another task, i.e. the one I'm enqueuing, executes. This is what I'm trying to confirm. –  Oct 19 '15 at 00:19
  • 3
    As you say, the main queue is a serial queue, so your current task will not be pre-empted and the order of execution is not indeterminate; tasks will be executed in the order they were submitted to the queue. This means that you cannot say, for certain, when the dispatched block will execute as you don't know what other tasks may be in the queue ahead of the one you added. All you can say for certain is that it will execute 'later' – Paulw11 Oct 19 '15 at 00:24
  • In that case, you should be able to write a quick test program, run it a thousand times and confirm the documented/expected behavior. I am assuming you only have two threads in this case. In the more general case where multiple threads may be calling dispatch_async, @Paulw11's comment about indeterminate order of submission applies. So in the end, you still should not really code based on the assumption of only two threads (someone may add another thread later). – kfmfe04 Oct 19 '15 at 00:24
  • The only safe assumption is, if you have multiple invocations of dispatch_async from a specific thread, those will be executed "in submission order". – kfmfe04 Oct 19 '15 at 00:31

2 Answers2

2

When does this block actually get called in this case? Does my current queue get pre-empted and the block run immediately, or does the current call stack unroll and the block gets called at the next event loop? Or something else?

In short, if you dispatch asynchronously to the main queue from the main queue, the dispatched block will not run until you yield back to the main run loop (and also after any other blocks dispatched to the main queue also finish).

Rob
  • 415,655
  • 72
  • 787
  • 1,044
1

From Grand Central Dispatch (GCD) Reference: dispatch_async

The target queue determines whether the block is invoked serially or concurrently with respect to other blocks submitted to that same queue.

From OperationQueues: Performing Tasks on the Main Thread

You can get the dispatch queue for your application’s main thread by calling the dispatch_get_main_queue function. Tasks added to this queue are performed serially on the main thread itself. Therefore, you can use this queue as a synchronization point for work being done in other parts of your application.

From these two pieces of information, we know the main queue is a serial dispatch queue and dispatch_async() will follow the rules of serial execution.

So the simple answer is the task will be run on the main queue sometime after the completion of the current context.


I couldn't find a official description of the run loop's internals, but rob mayoff a good breakdown.

Order of operations in runloop on iOS

Note that the run loop is structured so only one of these branches happens on each iteration:

  1. Ready timers fire, or
  2. Blocks on dispatch_get_main_queue() run, or
  3. A single version 1 source is dispatched to its callback.

If the context is an input source or a timer fire, then the task will happen in a different iteration of the run loop. If the context is a dispatched task, then the task may actually run within the same iteration of the run loop.

Community
  • 1
  • 1
Jeffery Thomas
  • 42,202
  • 8
  • 92
  • 117