Ответ
Потокобезопасный массив гарантирует корректность данных при конкурентном доступе из нескольких потоков. В Swift для этого можно использовать GCD (Grand Central Dispatch) с барьерными операциями.
Основной подход: Использовать DispatchQueue с атрибутом .concurrent.
- Запись выполняется асинхронно с флагом
.barrier, что делает её эксклюзивной. - Чтение выполняется синхронно для получения актуальных данных.
class ThreadSafeArray<Element> {
private var array: [Element] = []
private let queue = DispatchQueue(label: "threadSafe.array.queue", attributes: .concurrent)
func append(_ element: Element) {
queue.async(flags: .barrier) {
self.array.append(element)
}
}
var elements: [Element] {
return queue.sync {
return self.array
}
}
}
Почему это работает? Барьерная задача (flags: .barrier) ждёт завершения всех текущих задач в очереди и выполняется в одиночку, блокируя другие задачи на время записи. Это обеспечивает безопасность записи. Синхронное чтение (queue.sync) гарантирует, что возвращаемые данные будут соответствовать состоянию на момент вызова.
Альтернативы и нюансы:
- Для сценариев с интенсивной записью или более тонкого контроля можно использовать низкоуровневые примитивы:
NSLock,os_unfair_lockилиpthread_rwlock_t. - Реализация выше оптимизирована для частого чтения и редкой записи. Для полного набора операций (удаление, индексация) потребуется добавить аналогичные потокобезопасные методы.