Are Swift variables atomic?

前端 未结 6 1250
隐瞒了意图╮
隐瞒了意图╮ 2020-11-28 04:19

In Objective-C you have a distinction between atomic and nonatomic properties:

@property (nonatomic, strong) NSObject *nonatomicObject;
@property (atomic, st         


        
6条回答
  •  执笔经年
    2020-11-28 05:02

    Here is the atomic property wrapper that I use extensively. I made the actual locking mechanism a protocol, so I could experiement with different mechanisms. I tried semaphores, DispatchQueues, and the pthread_rwlock_t. The pthread_rwlock_t was chosen because it appears to have the lowest overhead, and a lower chance of a priority inversion.

    /// Defines a basic signature that all locks will conform to. Provides the basis for atomic access to stuff.
    protocol Lock {
        init()
        /// Lock a resource for writing. So only one thing can write, and nothing else can read or write.
        func writeLock()
        /// Lock a resource for reading. Other things can also lock for reading at the same time, but nothing else can write at that time.
        func readLock()
        /// Unlock a resource
        func unlock()
    }
    
    final class PThreadRWLock: Lock {
        private var rwLock = pthread_rwlock_t()
    
        init() {
            guard pthread_rwlock_init(&rwLock, nil) == 0 else {
                preconditionFailure("Unable to initialize the lock")
            }
        }
    
        deinit {
            pthread_rwlock_destroy(&rwLock)
        }
    
        func writeLock() {
            pthread_rwlock_wrlock(&rwLock)
        }
    
        func readLock() {
            pthread_rwlock_rdlock(&rwLock)
        }
    
        func unlock() {
            pthread_rwlock_unlock(&rwLock)
        }
    }
    
    /// A property wrapper that ensures atomic access to a value. IE only one thing can write at a time.
    /// Multiple things can potentially read at the same time, just not during a write.
    /// By using `pthread` to do the locking, this safer then using a `DispatchQueue/barrier` as there isn't a chance
    /// of priority inversion.
    @propertyWrapper
    public final class Atomic {
    
        private var value: Value
        private let lock: Lock = PThreadRWLock()
    
        public init(wrappedValue value: Value) {
            self.value = value
        }
    
        public var wrappedValue: Value {
            get {
                self.lock.readLock()
                defer { self.lock.unlock() }
                return self.value
            }
            set {
                self.lock.writeLock()
                self.value = newValue
                self.lock.unlock()
            }
        }
    
        /// Provides a closure that will be called synchronously. This closure will be passed in the current value
        /// and it is free to modify it. Any modifications will be saved back to the original value.
        /// No other reads/writes will be allowed between when the closure is called and it returns.
        public func mutate(_ closure: (inout Value) -> Void) {
            self.lock.writeLock()
            closure(&value)
            self.lock.unlock()
        }
    }
    

提交回复
热议问题