3

我试图了解使用 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 实现上述内容的最佳方法是什么?

4

1 回答 1

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 将这些包装的块推送到串行队列中。

于 2011-05-05T12:00:08.730 回答