IOS实现了一个死锁示例,该死锁示例导致UI死机

电脑杂谈  发布时间:2020-05-30 23:01:32  来源:网络整理

死锁避免 银行家算法_死锁举例_死锁

IOS实现了一个死锁示例,该死锁示例导致UI死机

现象

在启动APP一段时间(大约半小时左右)时,通常会发现APP界面显示为“冻死”. 同时后台输出:

[CocoaGoPush]WorkThreadProc end

死锁避免 银行家算法_死锁举例_死锁

这时,该应用程序处于“假死”状态. 当您单击屏幕上的任何位置时,没有任何响应. 除了打开和关闭屏幕(包括按Home键)外,iPhone没有其他响应. 当然,它无法解锁(但可以重新启动). 如果使用Xcode终止应用程序,iPhone将恢复正常.

注意: 应用程序使用CocoaGoPush框架.

发现

事实证明,该程序的主线程中发生了无限循环,导致UI变得无响应. 但是,当我单击“调试”工具栏中的“暂停”按钮以列出当前正在运行的线程时死锁举例,我发现问题并非如此,而是用于死锁. 调试暂停后,断点停止在以下句子:

死锁避免 银行家算法_死锁_死锁举例

app.gopushLock.lock()// MARK: yhy removed 这行导致主线程死锁

app.gopushLock是一个NSRecursiveLock对象:

let gopushLock = NSRecursiveLock()

NSRecursiveLock是一个递归锁. 这种类型的锁可以在同一线程中多次请求锁而不会导致死锁. 但是,如果程序员错误地在两个线程中使用了递归锁,则很容易导致“死锁”: 两个线程同时锁定同一个锁,并且同时发现该锁已被锁定,等待对方解锁,结果,两个线程都无法执行. 特别是,如果一方是主线程,则主线程被阻塞,UI处于无效状态. 在此示例中,还发现gopush所在的线程也已停止,并且不再继续监视gopush消息并维持心跳.

死锁避免 银行家算法_死锁_死锁举例

检查代码,发现代码在另一个地方使用了此递归锁:

NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler:{
      (response, data, error) -> Void in
      if (error != nil) {
        app.gopushLock.lock()
        app.isGoPushFetchingMessage = false
        app.gopushLock.unlock()
        println("-----------GoPush Message Guard fail to fetch offline message. err = \(error.localizedDescription)-----------")
        ...
 })

NSURLConection.sendAysnchronousRequest方法使请求在新线程中发送,因此app.gopushLock.lock()实际上是在子线程中调用的. 在主线程中调用另一个地方(第一段代码)死锁举例,导致“种族”.

已解决

死锁_死锁举例_死锁避免 银行家算法

方法一

注释主线程中的递归锁调用,仅在子线程中保留递归锁调用.

方法二

在主线程中使用不同的锁(例如专门为主线程重新定义NSLock)将其与子线程中的gopushLock区别开.

方法三

将gopushLock的类型从NSRecursiveLock更改为NSLock. 顾名思义,递归锁专门用于需要在循环或递归中同步的代码,但是它无法避免两个线程同时访问锁中的代码的情况. NSLock相反. 它可以防止两个线程同时访问锁中的代码,但是不能避免锁嵌套在同一线程中的同步代码中的情况. 检查第二次对递归锁的调用后,我发现没有必要使用递归锁,因为代码中既没有递归也没有循环. 因此,您可以安全地将gopushLock更改为NSLock而不是NSRecursiveLock.


本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-228137-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      • 周武帝
        周武帝

        批发价可低至3块钱

      • 王韫秀
        王韫秀

        老美本想现叫is打乱巴萨尔

      热点图片
      拼命载入中...