Проблема читателя и писателя – это классическая задача синхронизации доступа к общим данным в многопоточной среде.
Суть проблемы:
Требования:
Решения в iOS:
NSLock: Простейший механизм, но не оптимален для этой задачи, так как блокирует как чтение, так и запись.
NSRecursiveLock: Позволяет одному и тому же потоку получать блокировку несколько раз. Не применим.
NSCondition: Более гибкий механизм, позволяющий потокам ожидать выполнения определенных условий. Можно использовать для реализации логики читателей/писателей, но требует ручного управления блокировками и условиями.
Serial Dispatch Queue (GCD): Создание одной последовательной очереди для всех операций чтения и записи. Записи выполняются синхронно, чтение может выполняться асинхронно, но только после завершения предыдущих операций. Это простое решение, но не оптимальное по производительности для чтения, так как чтение не может быть параллельным.
swift
Concurrent Dispatch Queue с Barrier (GCD): Оптимальное решение в большинстве случаев. Используется конкурентная очередь для параллельного выполнения операций чтения. Для операций записи используется флаг .barrier. Когда операция с флагом .barrier ставится в очередь, она ожидает завершения всех предыдущих операций, затем выполняется сама, и пока она выполняется, никакие другие операции (ни чтение, ни запись) не выполняются. После завершения барьерной операции очередь снова становится конкурентной. Таким образом, чтение параллельно, а запись эксклюзивна.
swift
Это тот же код, что и для serial queue, но атрибут .concurrent делает очередь конкурентной. Флаг .barrier заставляет очередь вести себя как последовательная только для этой конкретной операции.
os_unfair_lock (iOS 10+): Низкоуровневая блокировка, более производительная, чем NSLock. Применима для реализации более сложной логики читателей-писателей вручную, если требуется максимальная производительность или специфичное поведение. Требует осторожного использования.
Выбор решения зависит от конкретных требований приложения, частоты операций чтения и записи, и необходимого уровня производительности. В большинстве случаев, использование concurrent dispatch queue с .barrier флагом является наиболее сбалансированным и рекомендуемым подходом в iOS.