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

rus*_*ell 7 cocoa cocoa-touch objective-c grand-central-dispatch

如果在3个不同的队列中调用dispatch_sync之间有什么区别吗?

1.

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

  });
Run Code Online (Sandbox Code Playgroud)

2.

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

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]
}
Run Code Online (Sandbox Code Playgroud)

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

bbu*_*bum 11

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

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

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

而且,根据定义,你不应该在乎.调用线程被阻止 - 无法做任何事情 - 直到dispatch_sync()返回.

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


Rob*_*Rob 6

请参阅dispatch_sync文档,注意事项

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

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

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

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

  • 调用哪个线程`dispatch_sync`并不重要.如果libdispatch*可以*在当前/调用线程上执行该块,它将会执行.它不能*在当前/调用线程上执行的情况将是队列具有目标,并且该目标具有线程关联(即从后台调用`dispatch_sync(dispatch_get_main_queue(),...)`的情况.线程 - 你永远不应该做,因为可能会出现死锁).可能还有其他情况,但是IME,在调用线程上执行块的`dispatch_sync`的情况是常见情况的绝大多数*. (3认同)
  • 从BG到MT的@Rob`dispatch_sync`:我在SO上一直看到它*.让我疯狂.已经看到它多次引起现实世界的僵局.此外,MT> ​​BG> MT不是唯一可以解锁的情况.如果MT被阻塞等待任何BG操作并且线程池耗尽,并且BG线程`dispatch_sync'到MT,则结果是相同的.我认为技术上它是一个"活锁",但效果是一样的; 你死在水里. (2认同)