Swift Utilities — Потокобезопасное свойство

от автора

За годы работы разработчиком iOS, я собрал множество инструментов и полезных штук, которые облегчают процесс разработки. В этой статье, я хочу поделиться одним из таких инструментов. Это будет не большая статья. Я покажу, как пользоваться этой утилитой, продемонстрирую её в действии. Надеюсь, что статья окажется полезной для вас.

При разработке очень важна безопасность данных при параллельном доступе к ним. В этой статье я покажу , как создать потокобезопасное свойство с использованием свойства-обёртки @SynchronizedLock.

@SynchronizedLock – это свойство-обёртка в Swift, обеспечивающая потокобезопасный доступ к переменной. Это означает, что при чтении и записи значения обёрнутой переменной, эти операции будут безопасно выполняться в разных потоках.

/// When using this property wrapper, you can ensure that reads and writes to the wrapped value are thread-safe. /// Example: /// ///```swift /// class SomeClass { /// ///     @SynchronizedLock var number: Int = 0 /// ///     func main() { ///         DispatchQueue.global().async { [weak self] in ///             for _ in 1 ... 1000 { ///                 self?.number = Int.random(in: 0 ..< 10) ///             } ///         } ///         DispatchQueue.global().async { [weak self] in ///             for _ in 1 ... 1000 { ///                 self?.number = Int.random(in: 0 ..< 10) ///             } ///         } ///     } ///``` @propertyWrapper public struct SynchronizedLock<Value> {     private var value: Value     private var lock = NSLock()      public var wrappedValue: Value {         get { lock.synchronized { value } }         set { lock.synchronized { value = newValue } }     }      public init(wrappedValue value: Value) {         self.value = value     } }  private extension NSLock {      @discardableResult     func synchronized<T>(_ block: () -> T) -> T {         lock()         defer { unlock() }         return block()     } }

Как это работает?

Для обеспечения потокобезопасности, @SynchronizedLock использует NSLock. Это обеспечивает, что только один поток может доступаться к переменной в данный момент времени. Блокировка освобождается только после завершения операции, позволяя следующему потоку войти в критическую секцию.

Пример использования

Рассмотрим класс SomeClass, где мы используем @SynchronizedLock для потокобезопасного доступа к переменной count.

class SomeClass {        @SynchronizedLock var number: Int = 0      func main() {         DispatchQueue.global().async { [weak self] in             for _ in 1 ... 1000 {                 self?.number = Int.random(in: 0 ..< 10)             }         }         DispatchQueue.global().async { [weak self] in             for _ in 1 ... 1000 {                 self?.number = Int.random(in: 0 ..< 10)             }         }     } }

В этом примере, два разных потока пытаются изменить значение number одновременно. Благодаря @SynchronizedLock, операции инкремента выполняются без конфликтов и состояние гонки.

Преимущества и ограничения

Основное преимущество @SynchronizedLock заключается в простоте использования и обеспечении безопасности данных в многопоточной среде. Однако использование блокировок может привести к снижению производительности, если они используются чрезмерно или в неоптимальном контексте.

Еще статьи Swift Utilities:


ссылка на оригинал статьи https://habr.com/ru/articles/774890/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *