tipos programar programación online objective los lenguajes lenguaje entre diferencias datos básicos apple objective-c swift

objective-c - programar - swift(lenguaje de programación)



¿Las variables de Swift son atómicas? (4)

Detalles

xCode 9.1, Swift 4

Campo de golf

Muestra de acceso atómico

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() } } } }

Uso

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

Resultado

En Objective-C tiene una distinción entre propiedades atómicas y no atómicas:

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

Desde mi entender, puede leer y escribir propiedades definidas como atómicas a partir de múltiples hilos de forma segura, mientras que escribir y acceder a propiedades no ativas o ivars de múltiples hilos al mismo tiempo puede dar como resultado un comportamiento indefinido, incluidos errores de acceso incorrectos.

Entonces, si tienes una variable como esta en Swift:

var object: NSObject

¿Puedo leer y escribir en esta variable en paralelo de forma segura? (Sin considerar el significado real de hacer esto).


Es muy pronto para suponer que no hay documentación de bajo nivel disponible, pero puede estudiar desde el ensamblaje. Hopper Disassembler es una gran herramienta.

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

Utiliza objc_storeStrong y objc_setProperty_atomic para nonatomic y atomic respectivamente, donde

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

usa swift_retain de libswift_stdlib_core y, al parecer, no tiene integrada la seguridad de subprocesos.

Podemos especular que palabras clave adicionales (similar a @lazy ) podrían ser introducidas más adelante.

Actualización 20/07/15 : de acuerdo con este blogpost en singletons swift environment puede hacer que ciertos casos sean seguros para usted, es decir:

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

Actualización 25/05/16 : esté atento a la rápida propuesta de evolución https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md - parece que es va a ser posible tener el comportamiento @atomic implementado por usted mismo.


Probablemente sea temprano para responder a esta pregunta. Actualmente, Swift carece de modificadores de acceso, por lo que no hay una forma obvia de agregar código que administre la concurrencia alrededor de un getter / setter de propiedades. Además, Swift Language aún no parece tener información sobre la simultaneidad. (También carece de KVO, etc.)

Creo que la respuesta a esta pregunta quedará clara en futuras versiones.


Swift no tiene construcciones de lenguaje en torno a la seguridad del hilo. Se supone que utilizará las bibliotecas proporcionadas para realizar su propia administración de seguridad de subprocesos. Hay una gran cantidad de opciones que tiene para implementar la seguridad de subprocesos, incluidos pthread mutexes, NSLock y dispatch_sync como mecanismo de exclusión mutua. Ver la reciente publicación de Mike Ash sobre el tema: https://mikeash.com/pyblog/friday-qa-2015-02-06-locks-thread-safety-and-swift.html Así que la respuesta directa a su pregunta de "Can Leo y escribo esta variable en paralelo de forma segura? " no es.