hga*_*ale 1 grand-central-dispatch ios dispatchsemaphore
假设我们有一个共享资源,许多不同的全局队列都可以访问该资源,并且为了解决这个问题,我们使用调度信号量来管理该访问。当这些全局队列之一告诉信号量等待时,信号量计数就会递减,并且该线程可以访问共享资源。是否有可能在信号量等待时,另一个(不同的)全局队列尝试访问这个共享资源,而GCD从其池中抓取的线程与为前一个队列(当前正在制作的队列)抓取的线程相同信号量等待)这会导致该线程死锁并阻止信号量计数重新递增?
简短回答:
\n\n是的,使用信号量可能会导致死锁,但并非出于您所建议的原因。
\n\n长答案:
\n\n如果您有某个正在等待信号量的分派任务,则该工作线程将被阻塞,直到收到信号并恢复执行并随后返回。因此,您不必担心另一个分派任务尝试使用同一线程,因为该线程已暂时从线程池中删除。您永远不必担心两个分派任务尝试同时使用同一线程。这不是僵局风险。
\n\n话虽如此,我们必须意识到线程池中工作线程的数量极其有限(目前每个 QoS 64 个)。如果耗尽可用的工作线程,则调度到 GCD(具有相同 QoS)的其他任何内容都无法运行,直到某些先前阻塞的工作线程再次可用。
\n\n考虑:
\n\nprint("start")\n\nlet semaphore = DispatchSemaphore(value: 0)\nlet queue = DispatchQueue.global()\nlet group = DispatchGroup()\nlet count = 10\n\nfor _ in 0 ..< count {\n queue.async(group: group) {\n semaphore.wait()\n }\n}\n\nfor _ in 0 ..< count {\n queue.async(group: group) {\n semaphore.signal()\n }\n}\n\ngroup.notify(queue: .main) {\n print("done")\n}\nRun Code Online (Sandbox Code Playgroud)\n\n效果很好。您有 10 个工作线程与这些调用相关wait,然后另外 10 个调度块调用signal,您\xe2\x80\x99 就可以了。
但是,如果增加到count100(称为 \xe2\x80\x9cthreadexplosion\xe2\x80\x9d 的情况),上述代码将永远不会自行解析,因为调用signal正在等待与所有线程相关的工作线程。那些wait电话。这些通过signal调用分派的任务都没有机会运行。而且,当你耗尽工作线程时,这通常是一个灾难性的问题,因为任何尝试使用 GCD(对于相同的 QoS)的东西都将无法运行。
顺便说一句,在线程爆炸场景中使用信号量只是导致死锁的一种特殊方式。但为了完整起见,\xe2\x80\x99s 值得注意的是,有很多方法可以用信号量造成死锁。最常见的示例是使用信号量(或调度组或其他)来等待某些异步进程,例如
\n\nlet semaphore = DispatchSemaphore(value: 0)\nsomeAsynchronousMethod {\n // do something useful\n\n semaphore.signal()\n}\nsemaphore.wait()\nRun Code Online (Sandbox Code Playgroud)\n\n如果 (a) 从主队列运行它,则可能会出现死锁;但是 (b) 异步方法也恰好在主队列上调用其完成处理程序。这是典型的信号量死锁。
\n\n我只使用了上面的线程爆炸示例,因为死锁并不完全明显。但显然有很多方法会导致信号量死锁。
\n| 归档时间: |
|
| 查看次数: |
990 次 |
| 最近记录: |