2011-04-08 56 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