你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> IOS 完成一個死鎖招致 UI 假死的例子

IOS 完成一個死鎖招致 UI 假死的例子

編輯:IOS開發綜合

IOS 完成一個死鎖招致 UI 假死的例子

景象

當 APP 啟動一段時間後(約半小時左右),常常會發現 App 界面呈現“凍死”的景象。同時後台輸入:

[CocoaGoPush]WorkThreadProc end

這時 App 出現“假死”形態,點擊屏幕任何中央沒有反響,iPhone 除了開屏關屏無任何呼應(包括按 Home 鍵),當然也無法解鎖(但可以重啟)。假如用 Xcode 終止使用順序,則 iPhone 又恢復正常。

注:App 運用了 CocoaGoPush 框架。

發現

原來以為是順序主線程中發生了死循環,招致 UI 無反響。但當我點擊 Debug 工具欄中的 Pause 按鈕,列出以後運轉的線程時,則發現問題並不是這樣,而是用於死鎖。調試暫停後,斷點停在了這一句:

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。

感激閱讀,希望能協助到大家,謝謝大家對本站的支持!

【IOS 完成一個死鎖招致 UI 假死的例子】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved