长话短说:在一般情况下,您无法知道您在哪个队列上运行,因为队列以分层树中的其他队列为目标。 (这很可能是不推荐使用dispatch_get_current_queue 的原因——对于“我在哪个队列上运行?”这个问题实际上没有一个答案)您可以通过调用[NSThread isMainThread] 来确定您是否在主队列上。当前推荐的跟踪您所在队列的机制是使用dispatch_queue_set_specific() 和dispatch_get_specific()。有关所有血腥细节,请参阅this question。
你说下面的引用不清楚:
发生的情况是所有这些后台线程开始排队
操作并使线程池饱和。同时,操作系统,在
主线程,在做自己的一些工作的过程中,调用
dispatch_sync,它阻止等待一个点在
线程池。死锁。
让我再次声明:GCD 可用的线程数量有限。当您调度一个块并开始执行时,它会“消耗”这些线程之一,直到它返回。如果执行块确实阻塞了 I/O 或以其他方式长时间休眠,您会发现自己处于所有可用线程都被消耗的情况。如果您的主线程随后尝试将dispatch_sync 阻止到另一个队列,并且没有更多线程可用,则您的主线程可能会阻塞等待线程可用。 (在原始引文中,“饥饿”比“饱和”更好。)
在一般情况下,严格来说,这种情况不是“死锁”,因为其他块最终可能会完成,并且它们正在使用的线程应该变得可用。不幸的是,根据经验观察,GCD 需要至少有一个可用的线程才能唤醒等待其他块完成的线程的队列。因此,在某些病理情况下,GCD 可能会饿死,从而有效地 陷入僵局。尽管链接页面上的示例可能确实符合死锁的严格定义,但并非所有最终被冻结的情况都符合;这并不能改变你被冻结的事实,因此可能不值得争论。
对此的标准建议是“不要那样做”,这有点无益。理想情况下,您永远不应该向 GCD 提交可能阻塞 I/O 或进入睡眠状态的块。在现实世界中,这可能至少是人们使用 GCD 的一半。我能说什么?并发很难。有关与 GCD 相关的线程限制的更多详细信息,您可以查看my answer over here。
听起来您在这里尝试实现的是递归锁。简短的版本是 GCD 队列不是锁。它们可以在某些情况下以近似锁的方式使用,但锁和任务队列是两个不同的东西,不是 100% 可互换的。
我开始相信,使用 GCD 队列来近似递归锁是不可能的,这种方式适用于所有可能的队列定位安排,并且不会比使用旧的队列导致更大的性能损失- 时尚的递归锁。有关使用 GCD 进行递归锁定的详细讨论,请查看 my answer over here。
编辑:特别是问题中的代码 sn-p,这就是发生的情况。想象一下线程限制是4。(这不是实际的限制,但是无论确切的限制是多少,主体都是一样的。)这是sn-p,供参考:
for (int i=0; i < A_BIG_NUMBER; i++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_sync(dispatch_get_main_queue(), ^{
// do something in the main queue
});
}
首先要记住的是,主线程是一个运行循环,其中发生了许多您没有直接导致发生的事情。让我们暂时假设主线程正忙于绘制。
循环的第一遍将从线程池中取出 1 个线程并运行入队的块。该线程将立即阻塞,因为它正在等待在主线程上做某事,但主线程仍在忙于绘图。此时 GCD 线程池中还剩下 3 个线程。
循环的第二遍将从线程池中取出 1 个线程并运行入队的块。该线程将立即阻塞,因为它正在等待在主线程上做某事,但主线程仍在忙于绘图。此时 GCD 线程池中还剩下 2 个线程。
循环的第三遍将从线程池中取出 1 个线程并运行入队的块。该线程将立即阻塞,因为它正在等待在主线程上做某事,但主线程仍在忙于绘图。此时GCD线程池中还剩1个线程。
循环的第四遍将从线程池中取出 1 个线程并运行入队的块。该线程将立即阻塞,因为它正在等待在主线程上做某事,但主线程仍在忙于绘图。此时 GCD 线程池中已经没有线程了。在主线程可以运行它们的dispatch_sync 块之前,这四个后台线程都不能继续运行。
现在,在主线程上,在绘图过程中,在您不可见的代码中(在 AppKit 或其他中)有一个对 dispatch_sync 的调用,以在其他一些后台队列上同步执行操作。此代码通常会从线程池中获取一个线程并完成其工作,最终主线程将继续。但在这种情况下,池中没有剩余线程。曾经存在的所有线程都在等待主线程空闲。但是主线程正在等待其中一个后台线程空闲。这是一个僵局。为什么某些操作系统代码会对后台队列执行dispatch_sync?我不知道,但链接文档中声称确实会发生这种情况(我完全相信。)