Swift4中使用Semaphore同步请求出现永久阻塞问题求助
解决DispatchSemaphore导致的应用永久锁死问题
你这是踩了信号量使用的经典死锁坑!问题核心在于 semaphore.wait() 和 OdooService.getProductsIds 的回调执行在了同一个线程(大概率是主线程)。
当你调用 semaphore.wait() 时,当前线程会被直接阻塞,而 OdooService.getProductsIds 的成功回调也需要在这个线程里执行——线程都被wait卡住了,回调根本没机会触发 semaphore.signal(),结果就是应用永远停在wait步骤,彻底锁死。
给你两个靠谱的解决方案:
方案1:调整线程,避免wait阻塞回调线程
把整个同步逻辑放到后台队列执行,这样wait阻塞的是后台线程,不会影响回调的正常执行:
class func syncProducts() { print("syncProducts() 1") let idsLocal = getProductsIds() let semaphore = DispatchSemaphore(value: 0) var idsCloud : [Int] = [] // 切换到后台队列执行异步等待逻辑 DispatchQueue.global(qos: .background).async { print("Getting cloud ids... 1") OdooService.getProductsIds { (params: [Int]) in print("SuccessBlock size ids: \(params.count) 1") idsCloud = params semaphore.signal() // 发送信号唤醒被wait阻塞的线程 } semaphore.wait() // 后台线程阻塞,不会影响主线程和回调执行 print("Depois do GetproductsIds: 1") // 如果需要更新UI或回到主线程处理结果,记得切换线程 DispatchQueue.main.async { // 这里写拿到idsCloud后的业务逻辑 } } }
方案2:用Swift async/await替代信号量(推荐)
如果你的项目支持iOS 15+/Swift 5.5+,直接用现代并发框架替代手动管理信号量,代码更简洁,还能从根源上避免死锁:
class func syncProducts() async { print("syncProducts() 1") let idsLocal = getProductsIds() print("Getting cloud ids... 1") // 把回调式API包装成async/await风格 let idsCloud = await withCheckedContinuation { continuation in OdooService.getProductsIds { params in continuation.resume(returning: params) } } print("SuccessBlock size ids: \(idsCloud.count) 1") print("Depois do GetproductsIds: 1") // 后续处理逻辑直接写在这里即可 }
额外提醒:
永远不要在主线程调用 semaphore.wait()!主线程被阻塞会直接导致UI卡死,用户体验极差,甚至可能被系统判定为无响应而杀死应用。
内容的提问来源于stack exchange,提问作者Augusto
相关产品推荐
相关产品推荐

