Какую задачу решает dispatch barrier
Что проверяют
Понимаете ли вы схему «много читателей, один писатель» и знаете ли ограничение барьера.
Как отвечать
Барьер решает задачу безопасного доступа к общему изменяемому состоянию, не отказываясь от параллельного чтения.
Механика: задача, отправленная с флагом барьера в конкурентную очередь, начинает выполняться только после завершения всех поставленных до неё задач и выполняется в одиночку. Все задачи после неё ждут её окончания и лишь потом снова идут параллельно.
Отсюда классическая схема:
private let queue = DispatchQueue(label: "cache", attributes: .concurrent)
private var storage: [String: Data] = [:]
func value(for key: String) -> Data? {
queue.sync { storage[key] } // читатели параллельно
}
func set(_ data: Data, for key: String) {
queue.async(flags: .barrier) { storage[key] = data } // писатель один
}Выгода по сравнению с обычной блокировкой или последовательной очередью: чтения, которых обычно большинство, идут одновременно, а сериализуется только запись.
Обязательные ограничения:
- барьер работает только на своей конкурентной очереди, созданной вами. На глобальных очередях он вырождается в обычную задачу, потому что очередь общая для всей системы, и остановить её было бы недопустимо;
- запись через
async, чтение черезsync: вызывающему нужен результат, а писателю ждать незачем; syncна ту же очередь изнутри неё самой даёт взаимную блокировку, это общее правило GCD.
Стоит добавить, что в новом коде эту задачу решает актор: он изолирует состояние и сериализует доступ автоматически, без ручных барьеров, хотя параллельного чтения не даёт.
Где спотыкаются
Ставят барьер на глобальную очередь и считают, что защитили состояние.
Создают очередь без attributes: .concurrent, и барьер теряет смысл.
Читают без синхронизации, защищая барьером только запись.
Вызывают sync на ту же очередь и получают зависание.