Queues are not bound to any specific thread

It all started with this snippet from @jspahrsummers

#import <Foundation/Foundation.h>

int main (int argc, const char **argv) {
  @autoreleasepool {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"is main thread? %i", (int)[NSThread isMainThread]);
      });
    });

    dispatch_main();
  }

  return 0;
}
2015-11-24 16:08:39.545 main[88889:21446128] is main thread? 0

with this comment:

[NSThread isMainThread] is probably not what you want!

and this is true. In general. With exceptions.

blocks submitted to the main queue in applications using dispatch_main() are not guaranteed to execute on the main thread.

The thing is that this applies to applications that use dispatch_main() like the one from the snippet. However for Cocoa applications, this is not a case because

Cocoa applications need not call dispatch_main().

Let's search how it is documented for Cocoa application:

dispatch_get_main_queue() function returns the queue associated with application’s main thread

This queue is created automatically for Cocoa applications and for applications that either call the dispatch_main() function or configure a run loop (using either the CFRunLoopRef type or an NSRunLoop object) on the main thread.[1]

This queue is created automatically on behalf of the main thread before main is called.

...and main run loop

The run loop for your application’s main thread is a crucial piece of infrastructure. As a result, the app frameworks provide the code for running the main application loop and start that loop automatically. [2]

and

Blocks submitted to the main queue will be executed as part of the "common modes" of the application's main NSRunLoop or CFRunLoop.

Ok, so for Cocoa application we have:

  1. Main thread
  2. Main queue associated with Main thread
  3. Main loop associated with Main thread

It's all should result in block execution in Main thread, shouldn't it? It is simply shown that snippet from the beginning will always return 1 when used with UIApplicationMain() or NSApplicationMain() instead of dispatch_main().

Check if main queue

When checking source code for libdispatch, this is quite a common comment to the functions:

Blocks submitted to the main queue MUST be run on the main thread.

and this is mostly compatibility mode with Cocoa (DISPATCH_COCOA_COMPAT).

Blocks submitted to the main queue MUST be run on the main thread

Why is it failing sometimes?

There is a problem discussed in ReactiveCocoa issue that checking for main thread is not enough to assume that this is main queue:

The question is WHY it is so?

However, don’t be fooled into thinking that queues, work units, and threads are tightly connected.[3]

Threads are reused. Queues reuse threads in general. If so, the Main thread can be reused by another queue (for example by concurrent queue) when Main thread is idle.

Conclusion

  • Main Queue IS bound to Main Thread.
  • Main Thread IS NOT bound to Main Queue.

That's why in general: Main Queue Thread != Main Thread

Good read about queues is this manual for dispatch_get_current_queue(), highly recomended.

comments?

References

  1. https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html ↩︎

  2. https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html ↩︎

  3. http://libdispatch.macosforge.org/trac/wiki/tutorial ↩︎