要回答您的確切問題:「我還有什麼可以用來研究爲什麼這些是僵局或我怎樣才能防止這些僵局發生?」,我只能回答一些非常簡單的想法一般是因爲你接近的問題很難:
- 從你認爲可能發生鎖定的任何地方添加NSLog語句。我發現使用
NSLog(@"%s ...YOUR DEBUG STATEMENT", __PRETTY_FUNCTION__)
可以幫助您確切地確定哪個函數被調用,以及從哪個隊列執行。
如果我們超越什麼工具都可以(這基本上是沒有什麼用處)的問題,那麼我留下了有關如何調試你描述的系統中的一些建議:
由於一些背景知識:我用2000多個動態下載和顯示的平滑滾動UITableViews動態下載並顯示可變高度的單元格,其中包含完全沒有由於數據處理或繪圖而導致的抖動或延遲的圖像。這個系統最初是使用CoreData設計的,但最終我們轉向直接使用SQLite來解決您遇到的多線程和並行性問題。我不主張切換到SQLite--這是我們在內部做出的決定,以提高速度並減少本地數據庫中的不一致性。我將其作爲我的答案的背景。
我會首先看看你使用Grand Central Dispatch。如果您使用任何dispatch_sync調用,請確保它們不會出現在阻塞運行線程的鏈中。我最初是這樣做的,以確保多個線程不會同時訪問某個託管對象上下文,並且在幾個小時的調試後才發現問題。這些可以偷偷靠近你,因爲dispatch_sync調用可能在其他函數調用的函數中很深。
我確實最終使用了一個事務性系統(非常SQL-y),它具有動態創建的單個查詢/更新隊列,可以確保一次不會發生太多操作。我也有一個完全不同的系統,它會使用一個單獨的串行讀隊列來快速讀取數據庫。如果可能,該隊列的MOC將從其他MOC鏡像。這很沉重,而且比較慢。由於該系統主要在後臺線程上處理,因此與用戶隔離。
CoreData通常很難多線程化。 SQLite稍微簡單一些,不過你必須圍繞它構建大量的特定於應用程序的體系結構才能使其可用。
如果您想發佈有關係統的其他細節,我也許能幫助更具體。希望這有用。
的一件事是,如果你遇到這種死鎖的同時調試Xcode中(我確實經常),則可以暫停調試器,看到一個堆棧跟蹤,往往是非常有用的(你會看到哪個線程是掛在什麼功能)。 – borrrden