Реализация модели одновременного чтения и записи с GCD - PullRequest
3 голосов
/ 08 апреля 2011

Я пытаюсь понять, как правильно использовать 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?

1 Ответ

3 голосов
/ 05 мая 2011

Думаю, у вас правильная идея.Концептуально, вам нужна частная параллельная очередь, в которую вы можете отправить «барьерные» блоки, так что барьерный блок ожидает, пока все ранее представленные блоки не завершат выполнение, а затем выполняет все сам.

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, чтобы отправить эти обернутыеблокирует последовательную очередь.

...