使用GCD实现并行读独占写入模型 [英] Implementing concurrent read exclusive write model with GCD

查看:155
本文介绍了使用GCD实现并行读独占写入模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想了解使用Grand Central Dispatch(GCD)来实现控制对资源的访问的并发读独占写入模型的正确方法。

I am trying to understand the proper way of using Grand Central Dispatch (GCD) to implement concurrent read exclusive write model of controlling access to a resource.

是一个NSMutableDictionary,读取很多,一次更新。什么是确保读取总是与字典的一致状态一起工作的正确方法是什么?当然,我可以使用一个队列和序列化对字典的所有读写访问,但这将不必要地序列化读取,应该允许同时访问字典。起初,这里使用的组听起来很有前途。我可以创建一个读组,并添加每个读操作。这将允许读取同时发生。然后当进行更新的时候,我可以dispatch_notify()或dispatch_wait()作为写操作的一部分,以确保所有读取完成之前,更新被允许继续。但是如何确保后续的读操作直到写操作完成才能开始?

Suppose there is a NSMutableDictionary that is read a lot and once in awhile updated. What is the proper way of ensuring that reads always work with consistent state of the dictionary? Sure I can use a queue and serialize all read and write access to the dictionary, but that would unnecessarily serialize reads which should be allowed to access the dictionary concurrently. At first the use of groups here sounds promising. I could create a 'read' group and add every read operation to it. That would allow reads to happen at the same time. And then when the time comes to do an update, I could dispatch_notify() or dispatch_wait() as part of a write operation to make sure that all reads complete before the update is allowed to go on. But then how do I make sure that a subsequent read operation does not start until the write operation completes?

下面是我上面提到的字典的例子:

R1:在0秒,读取需要5秒完成

R2:在2秒另一次读取需要5秒完成

W1:在4秒写操作需要访问字典3秒

R3:在6秒另一次读取需要5秒完成

W2:在8秒另一个写入操作也需要3秒完成

Here's an example with the dictionary I mentioned above:
R1: at 0 seconds, a read comes in which needs 5 seconds to complete
R2: at 2 seconds another read comes in which needs 5 seconds to complete
W1: at 4 seconds a write operation comes needing access to dictionary for 3 sec
R3: at 6 seconds another read comes in which needs 5 seconds to complete
W2: at 8 seconds another write operation comes in also needing 3 seconds to complete

理想情况下,上面应该显示如下:

R1从0秒开始,结束于5

R2从2秒开始,结束于7

W1从7秒开始,以10为结束

R3从10秒开始,结束于15

W2从15秒开始,到18时结束

Ideally the above should play out like this:
R1 starts at 0 seconds, ends at 5
R2 starts at 2 seconds, ends at 7
W1 starts at 7 seconds, ends at 10
R3 starts at 10 seconds, ends at 15
W2 starts at 15 seconds, ends at 18

注意:即使R3在6秒时,也不允许在W1之前启动,因为W1比较早。

Note: even though R3 came at 6 seconds, it was not allowed to start before W1 because W1 came earlier.

推荐答案

我认为你有正确的想法。在概念上,你想要的是一个私有并发队列,你可以提交障碍块,使得障碍块等待,直到所有先前提交的块已经完成执行,然后自己执行。

You've got the right idea, I think. Conceptually, what you want is a private concurrent queue that you can submit "barrier" blocks to, such that the barrier block waits until all previously submitted blocks have finished executing, and then executes all by itself.

GCD没有提供这种功能,但你可以通过将读/写请求包装在一些额外的逻辑中来模拟它,并通过中间序列队列

GCD doesn't (yet?) provide this functionality out-of-the-box, but you could simulate it by wrapping your read/write requests in some additional logic and funnelling these requests through an intermediary serial queue.

当读取请求到达串行队列的前面时, dispatch_group_async 队列。在写请求的情况下,您应该 dispatch_suspend 串行队列,并调用 dispatch_group_notify 将工作提交到并发队列只有在先前的请求完成执行后。

When a read request reaches the front of the serial queue, dispatch_group_async the actual work onto a global concurrent queue. In the case of a write request, you should dispatch_suspend the serial queue, and call dispatch_group_notify to submit the work onto the concurrent queue only after the previous requests have finished executing. After this write request has executed, resume the queue again.

下面这样可以让你开始(我没有测试过这个):

Something like the following could get you started (I haven't tested this):

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

Use dispatch_async to push these wrapped blocks onto a serial queue.

这篇关于使用GCD实现并行读独占写入模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆