Are Swift variables atomic?

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

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

From my understanding, you can safely read and write properties that are defined as atomic from multiple threads, while writing and accessing non-atomic properties or ivars from multiple threads can result in undefined behavior, including bad access errors.

So, if you have a variable like Swift:

 var object: NSObject 

Is it safe to read and write this variable in parallel? (Excluding the actual value of this).

+96
objective-c swift
Jun 11 '14 at 8:14
source share
4 answers

It is very early to assume that low-level documentation is not available, but you can learn assembly. Hopper Disassembler is a great tool.

 @interface ObjectiveCar : NSObject @property (nonatomic, strong) id engine; @property (atomic, strong) id driver; @end 

Uses objc_storeStrong and objc_setProperty_atomic for non-atomic and atomic, respectively, where

 class SwiftCar { var engine : AnyObject? init() { } } 

uses swift_retain from libswift_stdlib_core and apparently doesn't have built-in thread protection.

We can assume that additional keywords (similar to @lazy ) may be introduced later.

Update 07/20/15 : According to this blogpost on singleletons, a fast environment can make certain threads safe for you, i.e .:

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

Update 05/25/16 . Stay tuned for a quick development proposal https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md - it looks like it's going to probably have @atomic behavior implemented by you yourself .

+51
Jun 11 '14 at 9:00 a.m.
source share

Swift has no language constructs around thread safety. It is assumed that you will use the provided libraries to manage your flows. There are many ways to ensure thread safety, including the pthread, NSLock, and dispatch_sync mutexes as a mutual access mechanism. See a recent post by Mike Ash on: https://mikeash.com/pyblog/friday-qa-2015-02-06-locks-thread-safety-and-swift.html Therefore, a direct answer to your question "Can I is reading and writing this variable parallel safe? " No.

+10
Feb 08 '15 at 2:39
source share

It is probably early to answer this question. There are currently no access modifiers quickly, so there is no obvious way to add code that controls concurrency around the getter / setter property. Moreover, Swift Language has no concurrency information yet! (He also does not have KVO, etc.)

I think the answer to this question will become clear in future releases.

+7
Jun 11 '14 at 8:37
source share

the details

  • Xcode 9.1, Swift 4
  • Xcode 10.2.1 (10E1001), Swift 5

communication

Implemented types

  • Atomicray
  • Atomic integer
  • Atomicvalue

Meaning

 class Example { private lazy var semaphore = DispatchSemaphore(value: 1) func executeThreadSafeFunc1() { // Lock access. Only first thread can execute code below. // Other threads will wait until semaphore.signal() will execute semaphore.wait() // your code semaphore.signal() // Unlock access } func executeThreadSafeFunc2() { // Lock access. Only first thread can execute code below. // Other threads will wait until semaphore.signal() will execute semaphore.wait() DispatchQueue.global(qos: .background).async { // your code self.semaphore.signal() // Unlock access } } } 

Atomic Access Pattern

 class Atomic { let dispatchGroup = DispatchGroup() private var variable = 0 // Usage of semaphores func semaphoreSample() { // value: 1 - number of threads that have simultaneous access to the variable let atomicSemaphore = DispatchSemaphore(value: 1) variable = 0 runInSeveralQueues { dispatchQueue in // Only (value) queqes can run operations betwen atomicSemaphore.wait() and atomicSemaphore.signal() // Others queues await their turn atomicSemaphore.wait() // Lock access until atomicSemaphore.signal() self.variable += 1 print("\(dispatchQueue), value: \(self.variable)") atomicSemaphore.signal() // Unlock access } notifyWhenDone { atomicSemaphore.wait() // Lock access until atomicSemaphore.signal() print("variable = \(self.variable)") atomicSemaphore.signal() // Unlock access } } // Usage of sync of DispatchQueue func dispatchQueueSync() { let atomicQueue = DispatchQueue(label: "dispatchQueueSync") variable = 0 runInSeveralQueues { dispatchQueue in // Only queqe can run this closure (atomicQueue.sync {...}) // Others queues await their turn atomicQueue.sync { self.variable += 1 print("\(dispatchQueue), value: \(self.variable)") } } notifyWhenDone { atomicQueue.sync { print("variable = \(self.variable)") } } } // Usage of objc_sync_enter/objc_sync_exit func objcSync() { variable = 0 runInSeveralQueues { dispatchQueue in // Only one queqe can run operations betwen objc_sync_enter(self) and objc_sync_exit(self) // Others queues await their turn objc_sync_enter(self) // Lock access until objc_sync_exit(self). self.variable += 1 print("\(dispatchQueue), value: \(self.variable)") objc_sync_exit(self) // Unlock access } notifyWhenDone { objc_sync_enter(self) // Lock access until objc_sync_exit(self) print("variable = \(self.variable)") objc_sync_exit(self) // Unlock access } } } // Helpers extension Atomic { fileprivate func notifyWhenDone(closure: @escaping ()->()) { dispatchGroup.notify(queue: .global(qos: .utility)) { closure() print("All work done") } } fileprivate func runInSeveralQueues(closure: @escaping (DispatchQueue)->()) { async(dispatch: .main, closure: closure) async(dispatch: .global(qos: .userInitiated), closure: closure) async(dispatch: .global(qos: .utility), closure: closure) async(dispatch: .global(qos: .default), closure: closure) async(dispatch: .global(qos: .userInteractive), closure: closure) } private func async(dispatch: DispatchQueue, closure: @escaping (DispatchQueue)->()) { for _ in 0 ..< 100 { dispatchGroup.enter() dispatch.async { let usec = Int(arc4random()) % 100_000 usleep(useconds_t(usec)) closure(dispatch) self.dispatchGroup.leave() } } } } 

using

 Atomic().semaphoreSample() //Atomic().dispatchQueueSync() //Atomic().objcSync() 

Result

enter image description here

+4
Nov 17 '17 at 14:36
source share



All Articles