applicationWillTerminate死锁:应用终止时如何等待VZVirtualMachine停止?
解决VZVirtualMachine终止时的主线程阻塞问题
你的代码之所以卡壳,是因为semaphore.wait()直接阻塞了主线程,但stop的回调又被系统派发到主线程执行,形成了死锁:主线程等着回调发信号,回调却卡在队列里等主线程空闲。下面给你两种靠谱的解决思路:
方案一:后台线程处理stop(如果API允许)
如果VZVirtualMachine的stop方法支持在后台线程调用,那可以把stop操作放到后台队列,用DispatchGroup跟踪任务,在后台队列等待完成,完全不阻塞主线程:
func applicationWillTerminate(_ notification: Notification) { let runningEntities = runningEntities guard !runningEntities.isEmpty else { return } let stopGroup = DispatchGroup() let backgroundQueue = DispatchQueue(label: "com.yourapp.vm.stop.queue") runningEntities.forEach { entity in stopGroup.enter() backgroundQueue.async { entity.virtualMachine.stop { _ in stopGroup.leave() } } } // 在后台队列等待所有stop完成,不影响主线程 stopGroup.wait() }
方案二:主线程用RunLoop等待(必须在主线程调用stop时用)
如果stop必须在主线程调用,那就用DispatchGroup标记任务,然后通过RunLoop让主线程在等待时仍能处理回调事件,避免死锁:
func applicationWillTerminate(_ notification: Notification) { let runningEntities = runningEntities guard !runningEntities.isEmpty else { return } let stopGroup = DispatchGroup() var allVMsStopped = false runningEntities.forEach { entity in stopGroup.enter() entity.virtualMachine.stop { _ in stopGroup.leave() } } // 所有任务完成后在主线程标记状态 stopGroup.notify(queue: .main) { allVMsStopped = true } // 循环让RunLoop处理事件,直到所有虚拟机停止 while !allVMsStopped { RunLoop.current.run(until: Date().addingTimeInterval(0.1)) } }
原代码问题解析
原代码里DispatchSemaphore(value: -runningEntities.count)的逻辑本身没问题,但错在在主线程调用semaphore.wait()——主线程被完全阻塞后,stop的回调根本没机会执行,自然无法触发signal(),最终导致应用卡死无法正常终止。
内容的提问来源于stack exchange,提问作者Damian Dudycz
相关产品推荐
相关产品推荐

