我试图理解使用Grand Central Dispatch(GCD)实现控制对资源访问的并发读取独占写入模型的正确方法。
假设有一个NSMutableDictionary被大量读取并且偶尔更新一次。确保读取总是与字典的一致状态一起工作的正确方法是什么?当然,我可以使用队列并序列化对字典的所有读写访问,但这会不必要地序列化应该允许同时访问字典的读取。起初,这里使用群组听起来很有希望。我可以创建一个“读取”组并向其添加每个读取操作。这将允许读取同时发生。然后,当需要进行更新时,我可以将dispatch_notify()或dispatch_wait()作为写入操作的一部分,以确保在允许更新之前完成所有读取操作。但是,如何在写操作完成之前确保后续的读操作不会启动?
这是我上面提到的字典的例子:
R1:在0秒时,读数进入需要5秒才能完成
R2:在2秒钟进入另一个读数,需要5秒才能完成
W1:在4秒时,写操作需要访问字典3秒
R3:在6秒钟进入另一个读数,需要5秒才能完成
W2:在8秒时,另一个写入操作也需要3秒才能完成
理想情况下,上面应该是这样的:
R1从0秒开始,到5点结束
R2从2秒开始,到7点结束
W1从7秒开始,到10点结束
R3从10秒开始,到15点结束
W2从15秒开始,结束于18
注意:即使R3在6秒时出现,也不允许在W1之前启动,因为W1来得更早。
使用GCD实现上述目标的最佳方法是什么?
答案 0 :(得分: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将这些包装的块推送到串行队列。