Ответ
Dispatch Barrier — это механизм в Grand Central Dispatch (GCD), обеспечивающий эксклюзивный доступ к ресурсу при работе с concurrent (параллельной) очередью. Он временно превращает параллельную очередь в последовательную для выполнения конкретной задачи.
Принцип работы:
- До барьера: Задачи в concurrent очереди выполняются параллельно.
- Барьерная задача: Задача, отправленная с флагом
.barrier, ждет завершения всех уже запущенных задач. - Во время барьера: Очередь становится последовательной, и барьерная задача выполняется одна.
- После барьера: Очередь снова становится concurrent для следующих задач.
Типичное применение: Создание потокобезопасных структур данных с оптимизацией для частого чтения (reader-writer lock).
Пример (Потокобезопасный кэш в Swift):
class ThreadSafeCache<Key: Hashable, Value> {
private let concurrentQueue = DispatchQueue(label: "com.cache.queue", attributes: .concurrent)
private var storage: [Key: Value] = [:]
// Чтение (параллельное, не блокирующее)
func getValue(for key: Key) -> Value? {
return concurrentQueue.sync {
storage[key]
}
}
// Запись (эксклюзивная через барьер)
func setValue(_ value: Value, for key: Key) {
concurrentQueue.async(flags: .barrier) {
self.storage[key] = value
}
}
}
Важное ограничение: Барьеры работают только с пользовательскими concurrent очередями, созданными с атрибутом .concurrent. Использование с глобальными очередями (DispatchQueue.global()) или главной очередью (DispatchQueue.main) не имеет эффекта.
Ответ 18+ 🔞
Слушай, а вот есть такая штука — Dispatch Barrier. Ну, в GCD, понимаешь? Это как такой умный засранец, который умеет временно превращать параллельную толкучку в упорядоченную очередь из одного человека, чтобы тот мог спокойно сделать своё чёрное дело без помех.
Как эта магия работает, если на пальцах:
- До барьера: Все задачи в concurrent очереди носятся как угорелые, кто во что горазд, параллельно.
- Приходит Барьер: Задача, которую отправили с флагом
.barrier, такая: "Стоять, блядь! Все закончили то, что уже начали? А теперь все нахуй пошли, я буду работать один". И очередь замирает. - Во время барьера: Очередь становится последовательной, и эта барьерная сволочь делает что хочет, пока все остальные ждут.
- После барьера: Как только барьерная задача закончила — "Разбежались!" — и снова начинается привычный параллельный адок.
Где это, блядь, применить? Ну классика — сделать потокобезопасную хуйню, которую часто читают, но редко пишут. Типа кэша. Читать могут все сразу, а писать — только один, и чтобы в этот момент его никто не трогал.
Смотри, как это выглядит в коде (потокобезопасный кэш на Swift):
class ThreadSafeCache<Key: Hashable, Value> {
// Создаём свою concurrent очередь, а не берём первую попавшуюся глобальную
private let concurrentQueue = DispatchQueue(label: "com.cache.queue", attributes: .concurrent)
private var storage: [Key: Value] = [:]
// Чтение — быстрое, параллельное, без барьеров. Все могут лезть одновременно.
func getValue(for key: Key) -> Value? {
return concurrentQueue.sync {
storage[key]
}
}
// А вот запись — тут уже барьер, сука. Всех остановили, записали, потом отпустили.
func setValue(_ value: Value, for key: Key) {
concurrentQueue.async(flags: .barrier) {
self.storage[key] = value
}
}
}
И главное, ёпта, предупреждение, а то накосячите: Барьеры работают ТОЛЬКО с очередями, которые ты сам создал с атрибутом .concurrent. Если ты попробуешь впендюрить барьер в какую-нибудь системную глобальную очередь (DispatchQueue.global()) или, не дай бог, в главную (DispatchQueue.main) — нихуя не произойдёт, он проигнорируется. Так что не выёбывайся, создавай свою очередь и там уже хуячь барьеры.