Using this as a frame of reference, is there any reason why the following example {could not} / {would not} result in the GCD Thread Pool running exclusively on the main thread?
int main()
{
dispatch_queue_t myQueue = dispatch_queue_create("myQ",NULL); // create serial queue
//
dispatch_sync(myQueue, ^{/*some simple block*/});
....
dispatch_sync(myQueue, ^{/*some simple block*/});
}
My understanding is that GCD would try to optimize performance where possible, handing the blocks off (when beneficial) to any available thread. However monitoring this in xcode reveals that this may be running exclusively on the main thread. It is not until the dispatch calls become async
that a second thread is utilized.
I would just like to understand when/why a second thread may or may not be called. Previous to this I would assume that a second thread would always be called.
You are dispatching the blocks using dispatch_sync. dispatch_sync waits until the block has finished executing. So what you are doing is quite pointless, unless you are using that serial queue for synchronisation purposes. There can't be any concurrency. On the contrary, if there had been code already executing on the serial queue and possibly blocks already dispatched to it, your main thread would have to wait until the running block and all further dispatched blocks finished, and then would wait until your blocks are finished.
If you called dispatch_async, then the two blocks would be dispatched to the serial queue, would be executed one after the other (using one CPU), while your main thread would continue doing other things, using the other CPU.
If you called dispatch_async to a concurrent queue, then the two blocks would be executed in parallel, while your main thread could do other things, using up to three CPUs.
Now your code would "officially" run your blocks on another thread, while the main thread is blocked. Since thread switches are expensive, they are avoided if possible. So dispatch_sync to a serial queue will check if the queue is empty, and if it is empty, it will block the queue from dispatching, execute the block on the calling thread, and then unblock the queue. The behaviour is exactly the same as if the block had been dispatched, but it executes faster.