如果在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时,在主线程中执行块,而不考虑在哪个队列中调度它。那么为什么这个函数将队列作为参数,因为它不使用它。有人可以澄清一下吗?
答案 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