Is there any difference between if dispatch_sync is called in 3 different queue like
1.
dispatch_sync(dispatch_get_main_queue(),^(void){
NSLo
See dispatch_sync
documentation, which notes
As an optimization, this function invokes the block on the current thread when possible.
If you dispatch something synchronously, since the thread must wait for the dispatched code to complete, anyway, it will frequently run that code on the current thread. So if dispatched synchronously from the main thread, it will run on main thread. If dispatched synchronously from a background thread, it will run on that background thread.
As noted by ipmcc, a well-known exception is when a background thread dispatches something synchronously to the main thread. As the libdispatch source says:
It's preferred to execute synchronous blocks on the current thread due to thread-local side effects, garbage collection, etc. However, blocks submitted to the main thread MUST be run on the main thread.
For your problem: you call the dispatch_sync always in main queue, and if you wanna know why, see the following:
At first you need to pay attention to the description on of "dispatch_sync"
Submits a block to a dispatch queue for synchronous execution. Unlike dispatch_async, this function does not return until the block has finished. Calling this function and targeting the current QUEUE(NOT THREAD) results in deadlock.
#define logStep(step,queue) NSLog(@"step: %d at thread: %@ in -- queue: %s",step,[NSThread currentThread],dispatch_queue_get_label(queue));
// call the method in main thread within viewDidLoad or viewWillAppear ...
- (void)testDispatchSync{
//let's distinctly tell the 4 queues we often use at first
self.concurrentQ = dispatch_queue_create("com.shared.concurrent", DISPATCH_QUEUE_CONCURRENT);
self.serialQ = dispatch_queue_create("com.shared.serial", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t mainQ = dispatch_get_main_queue();
dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
logStep(1,mainQ) //we're in main thread and main queue, current queue IS main queue
// do a sync in main thread & concurrent queue
dispatch_sync(_concurrentQ, ^{
logStep(2,_concurrentQ)
});
// do a sync in main thread & serial queue
dispatch_sync(_serialQ, ^{
logStep(3,_serialQ)
});
//uncommenting the following code that you'wll see a crash will occur, because current queue is main queue
// dispatch_sync(mainQ, ^{
// logStep(4, mainQ)
// });
dispatch_async(_concurrentQ, ^{
// inside of the this scope, current queue is "_concurrentQ"
logStep(11,_concurrentQ)
// using sync in any queue here will be safe!
dispatch_sync(_concurrentQ, ^{
logStep(12,_concurrentQ)
});
dispatch_sync(_serialQ, ^{
logStep(13,_concurrentQ)
});
dispatch_sync(mainQ, ^{
logStep(14,mainQ)
});
dispatch_sync(globalQ, ^{
logStep(15,globalQ)
});
// using async in any queue here will be safe!
dispatch_async(_concurrentQ, ^{
logStep(111,_concurrentQ)
});
dispatch_async(_serialQ, ^{
logStep(112,_concurrentQ)
});
dispatch_async(mainQ, ^{
logStep(113,mainQ)
});
dispatch_async(globalQ, ^{
logStep(114,globalQ)
});
});
dispatch_async(_serialQ, ^{
// inside of the this scope, current queue is "_serialQ"
logStep(21,_serialQ)
// using async in any queue except current queue here will be safe!
dispatch_sync(_concurrentQ, ^{
logStep(22,_concurrentQ)
});
dispatch_sync(mainQ, ^{
logStep(23,mainQ)
});
dispatch_sync(globalQ, ^{
logStep(24,globalQ)
});
//uncommenting the following code that you'wll see a crash will occur, because current queue is "_serialQ"
// dispatch_sync(_serialQ, ^{ //app will die at here
// logStep(25,_serialQ)
// });
});
}
So we got the conclusion:
the key problem is that thread will be blocked while "dispatch_sync" running on current queue which is a serial queue at the same time.
main queue is also a serial queue so that it explained why you cann't call dispatch_sync in main thread
dispatch_sync
is a blocking operation. That is, the function will not return until the work represented in the block is completed.
When dispatched to an asynchronous queue -- like one of the global queues or a concurrent queue of your own making -- there is no reason to do anything but invoke the block on the thread that called dispatch_sync()
. Even in the case of invoking the block on a synchronous queue, the dispatch_sync()
is going to wait until completion anyway so, internally, it might as well stop until the rest of the work is done in the queue and then execute the block directly.
As it turns out, passing data from thread A to thread B is expensive. If the queue is in the state where execution can happen immediately, then dispatch_sync
will fast path the execution by simply calling the block on the thread that dispatch_sync
was called on.
And, by definition, you shouldn't care. The calling thread is blocked -- can't do a thing -- until dispatch_sync()
returns.
So, really, all of this is an implementation detail. GCD is free to execute the blocks on whatever threads it deems most appropriate. It just so happens that don't context switch is often the most important rule of figuring that out.