dispatch_sync()总是在主线程中执行块

时间:2014-09-24 15:19:46

标签: objective-c cocoa cocoa-touch grand-central-dispatch

如果在3个不同的队列中调用dispatch_sync(如

)之间有什么区别吗?

1

 dispatch_sync(dispatch_get_main_queue(),^(void){
      NSLog(@"this execute in main thread") // via [NSThread isMainThread]   

  });

2

dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void){
    NSLog(@"this also execute in main thread")  // via [NSThread isMainThread]
}

3

dispatch_queue_t queue;
queue = dispatch_queue_create("com.example.MyQueue", NULL);
dispatch_sync(queue, ^(void){
    NSLog(@"this also execute in main thread")  // via [NSThread isMainThread]
}

每当我调用dispatch_sync时,在主线程中执行块,而不考虑在哪个队列中调度它。那么为什么这个函数将队列作为参数,因为它不使用它。有人可以澄清一下吗?

3 个答案:

答案 0 :(得分:11)

dispatch_sync阻止操作。也就是说,在块中表示的工作完成之前,函数不会返回。

当调度到异步队列时 - 就像其中一个全局队列或你自己制作的并发队列一样 - 没有理由做任何事情而是调用调用的线程上的块dispatch_sync()。即使在同步队列上调用块的情况下,dispatch_sync()也会等到完成,所以在内部,它可能会停止,直到队列中的其余工作完成,然后执行直接阻止。

事实证明,将数据从线程A传递到线程B是昂贵的。如果队列处于可以立即执行的状态,那么dispatch_sync将通过简单地调用dispatch_sync被调用的线程上的块来快速执行执行。

而且,根据定义,你不应该在乎。 <{1}}返回后,调用线程被阻止 - 无法做任何事情。

所以,实际上,所有这些都是一个实现细节。 GCD可以在它认为最合适的任何线程上自由执行块。事实上没有上下文切换通常是解决这个问题的最重要规则。

答案 1 :(得分:6)

请参阅dispatch_sync文档,其中注明

  

作为优化,此函数会在可能的情况下调用当前线程上的块。

如果您同步调度某些内容,因为线程必须等待调度的代码完成,无论如何,它将经常在当前线程上运行该代码。因此,如果从主线程同步调度,它将在主线程上运行。如果从后台线程同步调度,它将在该后台线程上运行。

正如ipmcc所指出的,一个众所周知的例外是后台线程同步向主线程调度内容。正如libdispatch消息来源所说:

  

首选在当前线程上执行同步块   由于线程局部副作用,垃圾收集等。但是,   提交给主线程的块必须在主线程上运行。

答案 2 :(得分:0)

对于您的问题:您始终在主队列中调用dispatch_sync,如果您想知道原因,请参阅以下内容:

首先,您需要注意“dispatch_sync”

的描述
  

将一个块提交到调度队列以进行同步执行。与dispatch_async不同,    在块完成之前,此函数不会返回。    调用此函数并以当前队列为目标(NOT THREAD)会导致死锁。

#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)
        //        });
    });
}

所以我们得出结论:
关键问题是当“dispatch_sync”在当前队列(同时是串行队列)上运行时,线程将被阻塞。 主队列也是一个串行队列,因此它解释了为什么你不能在主线程中调用dispatch_sync

相关问题