You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:38:40