我试图了解使用 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 实现上述内容的最佳方法是什么?
我认为你的想法是正确的。从概念上讲,您想要的是一个私有并发队列,您可以向其中提交“屏障”块,这样屏障块就会等待,直到所有先前提交的块完成执行,然后自行执行所有块。
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将这些包装块推送到串行队列上。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)