这感觉像是一种过于复杂的思考方式,并且该描述中有很多不完全正确的小细节。具体来说,“它立即发生在当前线程上”是不正确的。
首先,让我们退后一步:和之间的区别dispatch_async
仅仅dispatch_sync
是当前线程是否等待它。但是,当您将某些内容分派到串行队列时,您应该始终想象它运行在 GCD 自己选择的单独工作线程上。是的,作为一种优化,有时dispatch_sync
会使用当前线程,但你无法保证这一事实。
其次,当你讨论时dispatch_sync
,你会说它“立即”运行。但这绝不能保证立即生效。如果一个线程dispatch_sync
对某个串行队列执行此操作,则该线程将阻塞,直到 (a) 当前在该串行队列上运行的任何块完成;(b) 该串行队列运行和完成的任何其他排队块;(c) 显然,线程 A 本身分派的块运行并完成。
现在,当您使用串行队列进行同步时,一些线程安全地访问内存中的某个对象,通常该同步过程非常快,因此等待线程通常会被阻塞一段可忽略不计的时间,因为它的调度块(和任何先前发送的块)来完成。但总的来说,说它会立即运行是一种误导。(如果它总是可以立即运行,那么您就不需要队列来同步访问)。
现在您的问题涉及“关键区域”,我假设您正在谈论一些代码,为了确保线程安全或出于类似的其他原因,必须同步这些代码。所以,在运行这段代码进行同步的时候,唯一的问题就是当前线程是否必须等待dispatch_sync
。dispatch_async
例如,一种常见的模式是说一个人可能会dispatch_async
写入某个模型(因为在继续之前不需要等待模型更新),但是dispatch_sync
从某个模型中读取(因为您显然不想继续,直到返回读取值)。
该同步/异步模式的进一步优化是读写器模式,其中允许并发读取但不允许并发写入。因此,您将使用并发队列,dispatch_barrier_async
即写入(为写入实现类似串行的行为),但dispatch_sync
使用读取(相对于其他读取操作享受并发性能)。