Why calling dispatch_sync on the current queue does not cause deadlocks
Apple's doc says: (concurrencyProgrammingGuide, page 49) Important: You should never call dispatch_sync or dispatch_sync_f from a task that runs on the same queue that you plan to pass to the function. This is especially important for sequential queues, which guarantee blocking, but should also be avoided for parallel queues.
but the code here doesn't deadlock, as I've run it many times:
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^(){
NSLog(@"in outer queue: %@", [NSThread currentThread]);
dispatch_sync(concurrentQueue, ^(){
NSLog(@"do someting thread: %@", [NSThread currentThread]);
});
});
However, we all know, in the context of the main thread, if we execute the code below it will deadlock on the main thread. so i'm confused why calling dispatch_sync on the same thread, one not dead end (code above), the other opposite (code below)?
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"________update__UI");
});
source to share
The sequential dispatch queue (main queue and user-created queues with the default flag) uses only one thread. Parallel dispatch queue (global queue created by queues with parallel flag) uses multiple threads (aka thread pool). The number of threads depends on the system, situation.
Take a look at the following code.
dispatch_async(queue, ^(){
/* Task 1 */
dispatch_sync(queue, ^(){
/* Task 2 */
});
});
Task 1 and Task 2 must run in the same order as in the queue. So task 1 is executed and then task 2.
In the Serial Send Queue, you dispatch_sync
will have to wait to execute task 2 on the thread running task 1 right now. DEADLOCK .
In a parallel dispatch queue, you dispatch_sync
usually do not need to wait for task 2 on a thread in the thread pool. But the number of threads in the thread pool is actually unlimited, sometimes dispatch_sync
you have to wait until some other task is finished. This is why " but should also be avoided for parallel queues ". dispatch_sync
also highly optimized, it uses the same task 1 thread for task 2 in some situation.
EDITED
So dispatch_sync
block means exactly the same as a normal call (function). In this case, DEADLOCK never happened.
EDITED
Test code.
#import <Foundation/Foundation.h>
void task2()
{
NSLog(@"task2: %@", [NSThread currentThread]);
}
void task1(dispatch_queue_t q)
{
NSLog(@"task1: %@", [NSThread currentThread]);
dispatch_sync(q, ^{
task2();
});
}
int main()
{
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
dispatch_async(q, ^{
task1(q);
});
dispatch_main();
return 0;
}
lldb log
(lldb) breakpoint set -l 6
(lldb) run
task1: <NSThread: 0x1001155a0>{number = 2, name = (null)}
task2: <NSThread: 0x1001155a0>{number = 2, name = (null)}
Process stopped
(lldb) bt
* thread #2: tid = 0x4dbcc, 0x0000000100000d34 a.out`task2 + 4 at a.m:5, queue = 'com.apple.root.default-qos', stop reason = breakpoint 1.1
* frame #0: 0x0000000100000d34 a.out`task2 + 4 at a.m:5
frame #1: 0x0000000100000dc5 a.out`__task1_block_invoke(.block_descriptor=<unavailable>) + 21 at a.m:12
frame #2: 0x00007fff8d6d6c13 libdispatch.dylib`_dispatch_client_callout + 8
frame #3: 0x00007fff8d6e19a1 libdispatch.dylib`_dispatch_sync_f_invoke + 39
frame #4: 0x0000000100000da3 a.out`task1(q=0x00007fff79749b40) + 67 at a.m:11
task1
the function calls the function task2
through the libdispatch APIs, but it is almost the same as a normal function call.
source to share