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");
    });

      

+3


source to share


2 answers


dispatch_get_global_queue()

returns the system global parallel queue.



+4


source


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.

enter image description here

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.

+3


source







All Articles