the programming language documentación developer descargar apple ios swift swift3

ios - programming - swift download



Seguridad de subprocesos para un getter y setter en un singleton (2)

Tiene razón en que esos captadores que ha escrito no son seguros para subprocesos. En Swift, la forma más sencilla (de la manera más segura) de lograr esto en este momento es utilizar las colas de Grand Central Dispatch como mecanismo de bloqueo. La manera más simple (y más fácil de razonar) de lograr esto es con una cola serial básica.

class MySingleton { static let shared = MySingleton() // Serial dispatch queue private let lockQueue = DispatchQueue(label: "MySingleton.lockQueue") private var _myName: String var myName: String { get { var result: String! lockQueue.sync { result = self._myName } return result } set { lockQueue.sync { self._myName = newValue } } } private init() { _myName = "initial name" } }

El uso de una cola de envío en serie garantizará la ejecución del primero en entrar, primero en salir, y también logrará un "bloqueo" de los datos. Es decir, los datos no se pueden leer mientras se modifican. En este enfoque, utilizamos la sync para ejecutar las lecturas y escrituras reales de los datos, lo que significa que la persona que llama siempre se verá obligada a esperar su turno, de forma similar a otras primitivas de bloqueo.

Nota: Este no es el enfoque más eficiente, pero es fácil de leer y comprender. Es una buena solución de propósito general para evitar las condiciones de carrera, pero no tiene la intención de proporcionar sincronización para el desarrollo de algoritmos paralelos.

Fuentes: https://mikeash.com/pyblog/friday-qa-2015-02-06-locks-thread-safety-and-swift.html ¿Qué es el Swift equivalente a Objective-C "@synchronized"?

Creé un singleton simple en Swift 3:

class MySingleton { private var myName: String private init() {} static let shared = MySingleton() func setName(_ name: String) { myName = name } func getName() -> String { return myName } }

Como he hecho que el init() privado, y también que la instancia shared declarada sea static let , creo que el inicializador es seguro para subprocesos. Pero, ¿qué pasa con las funciones getter y setter para myName , están seguras de subprocesos?


Una forma ligeramente diferente de hacerlo (y esto es de un Xcode 9 Playground) es usar una cola simultánea en lugar de una cola en serie.

final class MySingleton { static let shared = MySingleton() private let nameQueue = DispatchQueue(label: "name.accessor", qos: .default, attributes: .concurrent) private var _name = "Initial name" private init() {} var name: String { get { var name = "" nameQueue.sync { name = _name } return name } set { nameQueue.async(flags: .barrier) { self._name = newValue } } } }

  • El uso de una cola concurrente significa que múltiples lecturas de múltiples hilos no se bloquean entre sí. Como no hay mutación al obtener, el valor se puede leer al mismo tiempo, porque ...
  • Estamos estableciendo los nuevos valores usando un .barrier asíncrono .barrier . El bloqueo se puede realizar de forma asíncrona porque no es necesario que el llamante espere a que se establezca el valor. El bloque no se ejecutará hasta que todos los demás bloques en la cola concurrente antes de que se haya completado. Por lo tanto, las lecturas pendientes existentes no se verán afectadas mientras este setter esté esperando su ejecución. La barrera significa que cuando comienza a funcionar, no se ejecutarán otros bloques. Efectivamente, convirtiendo la cola en una cola en serie mientras dure el colocador. No se pueden realizar más lecturas hasta que se complete este bloque. Cuando el bloque se ha completado se ha establecido el nuevo valor, cualquier getters agregado después de este setter ahora puede ejecutarse simultáneamente.