В
Swift существует несколько способов защиты данных от гонки (data races):
NSLock,
DispatchSemaphore, последовательные очереди (DispatchQueue). Но на
WWDC24 компания
Apple представила новый
Synchronization Framework, включающий современный
Mutex - стандартизированную блокировку взаимного исключения.
В чем разница между Lock и Mutex:
- Lock: общее название механизмов синхронизации (например, NSLock, os_unfair_lock).
- Mutex: частный случай блокировки, гарантирующий, что только один поток может владеть ресурсом в данный момент.
Ключевая особенность Mutex:
- Строгое владение - разблокировать может только тот поток, который заблокировал.
- Поддержка Sendable, что делает его удобным для Swift Concurrency.
Пример использования:
Пример защиты счетчика:
final class Counter {
private let count = Mutex<Int>(0) // Обернули значение в Mutex
var currentCount: Int {
count.withLock { $0 } // Безопасное чтение
}
func increment() {
count.withLock { $0 += 1 } // Атомарная операция
}
func decrement() throws {
try count.withLock {
guard $0 > 0 else { throw Error.reachedZero }
$0 -= 1
}
}
}
Mutex vs Actor:
- Actor: идеален для асинхронного доступа, но требует await.
- Mutex: синхронный, подходит для legacy кода или когда нельзя использовать async/await.
Когда выбирать Mutex:
- Нужна мгновенная синхронная блокировка.
- Работа с не Sendable типами (например NSBezierPath).
- Интеграция с кодом, не поддерживающим Concurrency.
Важно:
- Доступен с iOS 18 и macOS 15.
- Не заменяет Actor, а дополняет инструментарий для работы с многопоточностью.
Mutex из
Synchronization Framework - это современный, безопасный и эффективный способ защиты данных в
Swift.