Objective c Swift变量是原子变量吗?

Objective c Swift变量是原子变量吗?,objective-c,swift,Objective C,Swift,在Objective-C中,原子和非原子属性之间存在区别: @property (nonatomic, strong) NSObject *nonatomicObject; @property (atomic, strong) NSObject *atomicObject; 据我所知,您可以安全地从多个线程读取和写入定义为原子的属性,而同时从多个线程写入和访问非原子属性或IVAR可能会导致未定义的行为,包括错误的访问错误 如果Swift中有这样一个变量: var object: NSObjec

在Objective-C中,原子和非原子属性之间存在区别:

@property (nonatomic, strong) NSObject *nonatomicObject;
@property (atomic, strong) NSObject *atomicObject;
据我所知,您可以安全地从多个线程读取和写入定义为原子的属性,而同时从多个线程写入和访问非原子属性或IVAR可能会导致未定义的行为,包括错误的访问错误

如果Swift中有这样一个变量:

var object: NSObject

我可以安全地并行读取和写入此变量吗?(没有考虑这样做的实际意义)。

回答这个问题可能还为时过早。目前,swift缺少访问修饰符,因此没有明显的方法添加代码来管理围绕属性getter/setter的并发性。此外,Swift语言似乎还没有关于并发性的任何信息!(它还缺少KVO等)


我认为这个问题的答案将在未来的版本中变得清晰

现在假设还为时尚早,因为没有可用的低级文档,但您可以从汇编中学习。这是一个很好的工具

@interface ObjectiveCar : NSObject
@property (nonatomic, strong) id engine;
@property (atomic, strong) id driver;
@end
分别对非原子和原子使用
objc_storeStrong
objc_setProperty_atomic
,其中

class SwiftCar {
    var engine : AnyObject?    
    init() {
    }
}
使用
libswift\u stdlib\u core
中的
swift\u retain
,显然没有内置线程安全性

我们可以推测,以后可能会引入其他关键字(类似于
@lazy

更新7/20/15:根据此swift环境,您可以确保某些情况下的线程安全,即:

class Car {
    static let sharedCar: Car = Car() // will be called inside of dispatch_once
}

private let sharedCar: Car2 = Car2() // same here
class Car2 {

}

更新05/25/16:请密切关注swift演进计划-看起来有可能由您自己实现
@atomic
行为。

swift没有关于线程安全的语言结构。假设您将使用提供的库来执行自己的线程安全管理。 在实现线程安全时,有很多选项,包括pthread互斥、NSLock和作为互斥机制的dispatch_sync。请参阅Mike Ash最近关于该主题的帖子: 因此,对于您的问题“我可以安全地并行读取和写入此变量吗?”的直接答案是否定的。

Details
  • 代码9.1,Swift 4
  • 代码10.2.1(10E1001),Swift 5
链接
实现类型
  • -提供安全多线程访问值的通用包装器
主旨 原子访问示例 结果
这是我广泛使用的原子属性包装器。我把实际的锁定机制做成了一个协议,所以我可以用不同的机制进行实验。我尝试了信号量、
DispatchQueues
pthread\u rwlock\u t
。之所以选择
pthread\u rwlock\u t
,是因为它的开销最低,优先级反转的可能性也较低

/// 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<Value> {

    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()
    }
}
///定义所有锁都将遵循的基本签名。为原子访问提供了基础。
协议锁{
init()
///锁定资源进行写入。因此,只有一件东西可以写入,其他任何东西都不能读取或写入。
func writeLock()
///锁定资源以进行读取。其他东西也可以同时锁定以进行读取,但此时其他任何东西都不能写入。
func readLock()
///解锁资源
func解锁()
}
最后一个类PThreadRWLock:Lock{
private var rwLock=pthread\u rwLock\u t()
init(){
guard pthread_rwlock_init(&rwlock,nil)==0{
预处理失败(“无法初始化锁”)
}
}
脱硝{
pthread\u rwlock\u销毁(&rwlock)
}
func writeLock(){
pthread\u rwlock\u wrlock(&rwlock)
}
func readLock(){
pthread\u rwlock\u rdlock(&rwlock)
}
func解锁(){
pthread\u rwlock\u解锁(&rwlock)
}
}
///确保对值进行原子访问的属性包装器。一次只能写一件事。
///可以同时读取多个内容,但不能在写入期间读取。
///通过使用'pthread'进行锁定,这比使用'DispatchQueue/barrier'更安全,因为没有机会
///优先权倒置。
@房地产经纪人
公共最终类原子{
私有var值:value
private let lock:lock=PThreadRWLock()
public init(wrappedValue:value){
自我价值=价值
}
公共var wrappedValue:Value{
得到{
self.lock.readLock()
延迟{self.lock.unlock()}
回归自我价值
}
设置{
self.lock.writeLock()
self.value=newValue
self.lock.unlock()
}
}
///提供将被同步调用的闭包。此闭包将在当前值中传递
///并且可以自由修改。任何修改都将保存回原始值。
///在调用闭包和它返回之间不允许进行其他读/写操作。
public func mutate(u闭包:(inout值)->Void){
self.lock.writeLock()
闭包(&值)
self.lock.unlock()
}
}

从Swift 5.1开始,您可以使用属性包装器为您的属性创建特定的逻辑。这是原子包装器实现:

@propertyWrapper
struct atomic<T> {
    private var value: T
    private let lock = NSLock()

    init(wrappedValue value: T) {
        self.value = value
    }

    var wrappedValue: T {
      get { getValue() }
      set { setValue(newValue: newValue) }
    }

    func getValue() -> T {
        lock.lock()
        defer { lock.unlock() }

        return value
    }

    mutating func setValue(newValue: T) {
        lock.lock()
        defer { lock.unlock() }

        value = newValue
    }
}

我想在将来,也许我们可以使用原子的或非原子的。或者只是默认的原子。(Swift是如此的不完整,我们现在不能说太多)在我看来,默认情况下,他们将使所有内容都非原子化,并且可能会提供一个特殊功能来制作原子内容。另外,
atomic
通常被认为不足以与属性进行线程安全交互,除了简单的数据类型。对于对象,通常使用锁(例如,
NSLock
@synchronized
)或GCD队列(例如带有“读写器”模式的串行队列或并发队列)跨线程同步访问,
Atomic().semaphoreSample()
//Atomic().dispatchQueueSync()
//Atomic().objcSync()
/// 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<Value> {

    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()
    }
}
@propertyWrapper
struct atomic<T> {
    private var value: T
    private let lock = NSLock()

    init(wrappedValue value: T) {
        self.value = value
    }

    var wrappedValue: T {
      get { getValue() }
      set { setValue(newValue: newValue) }
    }

    func getValue() -> T {
        lock.lock()
        defer { lock.unlock() }

        return value
    }

    mutating func setValue(newValue: T) {
        lock.lock()
        defer { lock.unlock() }

        value = newValue
    }
}
class Shared {
    @atomic var value: Int
...
}