2011-04-08 43 views
3

我想了解使用Grand Central Dispatch(GCD)實現控制對資源訪問的併發讀獨佔寫模型的正確方法。使用GCD實現併發讀獨佔寫模型

假設有一個NSMutableDictionary被讀取很多,並在一段時間內更新。確保閱讀始終與字典的一致狀態一起工作的正確方法是什麼?當然,我可以使用一個隊列並序列化所有對字典的讀寫訪問權限,但是這會不必要地串行化讀取,這些讀取應該被允許同時訪問字典。起初在這裏使用團體聽起來很有希望。我可以創建一個「讀」組,並將每個讀操作添加到它。這將允許讀取同時發生。然後,當需要進行更新時,我可以將dispatch_notify()或dispatch_wait()作爲寫入操作的一部分,以確保在更新被允許繼續之前完成所有讀取操作。但是,如何才能確保後續的讀取操作在寫入操作完成之前不會開始?

下面是與我上面提到的詞典的示例:
R1:0秒,讀出來自在需要5秒至完成
R2:在2秒時另一讀取附帶在需要5秒完成
W1:在4秒鐘的寫入操作需要訪問字典3秒
R3:在6秒時,另一次讀入需要5秒鐘完成
W2:在8秒鐘時,另一寫入操作進入也需要3秒完成

理想情況下,abo已經應該發揮出這樣的:
R1開始於0秒,在5
R2結束開始於2秒,7
W1結束開始於7秒,在10
R3結束開始於10秒,結束於15
W2從15秒開始,結束於18

注意:即使R3在6秒時出現,也不允許在W1之前開始,因爲W1較早出現。

用GCD實現上述的最好方法是什麼?

回答

3

我認爲你有正確的想法。從概念上講,你想要的是一個私有併發隊列,你可以將「障礙」塊提交給這個障礙塊,以便障礙塊等待,直到所有先前提交的塊都完成執行,然後自行執行。

GCD還沒有(現在?)開箱即用地提供此功能,但您可以通過將讀/寫請求封裝在一些附加邏輯中並通過中間串行隊列發送這些請求來模擬它。

當讀請求到達串行隊列的前端時,dispatch_group_async實際工作到全局併發隊列中。在寫入請求的情況下,應該在串行隊列中使用dispatch_suspend,並且只有在前一個請求完成執行後才調用dispatch_group_notify將工作提交到併發隊列中。在寫入請求執行後,再次恢復隊列。

像下面這樣可以讓你開始(我沒有測試過這一點):

dispatch_block_t CreateBlock(dispatch_block_t block, dispatch_group_t group, dispatch_queue_t concurrentQueue) { 
    return Block_copy(^{ 
     dispatch_group_async(concurrentQueue, group, block); 
    }); 
} 

dispatch_block_t CreateBarrierBlock(dispatch_block_t barrierBlock, dispatch_group_t group, dispatch_queue_t concurrentQueue) { 
    return Block_copy(^{ 
     dispatch_queue_t serialQueue = dispatch_get_current_queue(); 
     dispatch_suspend(serialQueue); 
     dispatch_group_notify(group, concurrentQueue, ^{ 
      barrierBlock(); 
      dispatch_resume(serialQueue); 
     }); 
    }); 
} 

使用dispatch_async這些包裹塊推到一個串行隊列。

+0

尼克,謝謝你的回答!我還沒有測試過你的解決方案,但看起來它會起作用! (唯一需要修正的是我們需要Block_copy傳遞給CreateBlock和CreateBarrierBlock的塊,因爲這些塊不會同步執行) – Yurie 2011-05-14 14:44:09

+2

Apple現在提供iOS 4.3/OS X 10.7以上版本的屏障塊API。您需要創建一個具有屬性DISPATCH_QUEUE_CONCURRENT的隊列,並且無論何時想要將阻擋塊添加到隊列中,都可以使用dispatch_barrier_async()或dispatch_barrier_sync()。該文檔位於中。 – 2011-06-03 05:17:47

+0

@Christopher尼斯發現!我沒有意識到蘋果公司已經公佈了。 – 2011-06-03 11:25:16