He buscado en el libro Swift, pero no puedo encontrar la versión Swift de @synchronized. ¿Cómo hago exclusión mutua en Swift?
concurrency
mutex
swift
Cuenta
fuente
fuente

removeFirst()?Respuestas:
Puedes usar GCD. Es un poco más detallado que
@synchronized, pero funciona como un reemplazo:fuente
Estaba buscando esto yo mismo y llegué a la conclusión de que todavía no hay una construcción nativa dentro de Swift para esto.
Creé esta pequeña función auxiliar basada en algunos de los códigos que he visto de Matt Bridges y otros.
El uso es bastante sencillo
Hay un problema que he encontrado con esto. Pasar una matriz como el argumento de bloqueo parece causar un error de compilación muy obtuso en este punto. De lo contrario, parece funcionar como se desea.
fuente
@synchronizedbloque muy bien, pero tenga en cuenta que no es idéntica a una declaración verdadero bloque incorporado como el@synchronizedbloque en Objective-C, porquereturnybreakdeclaraciones trabajo ya no saltar de la función / bucle que rodea al igual lo haría si fuera una declaración ordinaria.deferpalabra clave para garantizar queobjc_sync_exitse llame incluso si seclosurelanza.Me gusta y utilizo muchas de las respuestas aquí, así que elegiría la que mejor funcione para usted. Dicho esto, el método que prefiero cuando necesito algo como el objetivo-c
@synchronizedutiliza ladeferdeclaración introducida en swift 2.Lo bueno de este método, es que su sección crítica puede salir del bloque de contención de cualquier manera deseada (por ejemplo,
return,break,continue,throw), y "las declaraciones dentro de la declaración de aplazamiento se ejecutan sin importar cómo se transfiere el control del programa." 1fuente
lock? ¿Cómo selockinicializa?lockes cualquier objeto objetivo-c.Puede intercalar declaraciones entre
objc_sync_enter(obj: AnyObject?)yobjc_sync_exit(obj: AnyObject?). La palabra clave @synchronized está utilizando esos métodos debajo de las cubiertas. es decirfuente
objc_sync_enteryobjc_sync_exitson métodos definidos en Objc-sync.h y son de código abierto: opensource.apple.com/source/objc4/objc4-371.2/runtime/…objc_sync_enter(…)yobjc_sync_exit(…)son encabezados públicos proporcionados por iOS / macOS / etc. API (parece que están dentro….sdkde la rutausr/include/objc/objc-sync.h) . La forma más fácil de averiguar si algo es una API pública o no es (en Xcode) escribir el nombre de la función (por ejemploobjc_sync_enter(), no es necesario especificar argumentos para las funciones C) , luego intente hacer clic con el comando. Si le muestra el archivo de encabezado para esa API, entonces está bien (ya que no podría ver el encabezado si no fuera público) .El análogo de la
@synchronizeddirectiva de Objective-C puede tener un tipo de retorno arbitrario y un buenrethrowscomportamiento en Swift.El uso de la
deferdeclaración permite devolver directamente un valor sin introducir una variable temporal.En Swift 2 agregue el
@noescapeatributo al cierre para permitir más optimizaciones:Basado en las respuestas de GNewc [1] (donde me gusta el tipo de retorno arbitrario) y Tod Cunningham [2] (donde me gusta
defer).fuente
SWIFT 4
En Swift 4 puede usar las colas de despacho de GCD para bloquear recursos.
fuente
.serialParece no estar disponible. Pero.concurrentestá disponible. : /myObject.state = myObject.state + 1simultáneamente, no contaría las operaciones totales, sino que arrojaría un valor no determinista. Para resolver ese problema, el código de llamada debe estar envuelto en una cola en serie para que tanto la lectura como la escritura ocurran atómicamente. Por supuesto, Obj-c@synchronisedtiene el mismo problema, por lo que su implementación es correcta.myObject.state += 1es una combinación de una operación de lectura y luego de escritura. Algún otro hilo aún puede interponerse para establecer / escribir un valor. Según objc.io/blog/2018/12/18/atomic-variables , sería más fácil ejecutarloseten un bloque / cierre de sincronización y no bajo la variable misma.Utilizando la respuesta de Bryan McLemore, la extendí para apoyar objetos que arrojan una mansión segura con la habilidad de aplazamiento Swift 2.0.
fuente
rethrowspara simplificar el uso con cierres sin tirar (no es necesario usartry), como se muestra en mi respuesta .Para agregar la funcionalidad de retorno, puede hacer esto:
Posteriormente, puede llamarlo usando:
fuente
Swift 3
Este código tiene la capacidad de reingreso y puede funcionar con llamadas de función asincrónicas. En este código, después de llamar a someAsyncFunc (), se procesará otro cierre de función en la cola en serie, pero semaphore.wait () bloqueará hasta que se llame a signal (). internalQueue.sync no debe usarse, ya que bloqueará el hilo principal si no me equivoco.
objc_sync_enter / objc_sync_exit no es una buena idea sin manejo de errores.
fuente
En la sesión 414 "Comprender los bloqueos y los registros de bloqueos" de la WWDC 2018, muestran la siguiente manera utilizando DispatchQueues con sincronización.
En swift 4 debería ser algo como lo siguiente:
De todos modos, también puede hacer lecturas más rápidas utilizando colas concurrentes con barreras. Las lecturas de sincronización y asíncrona se realizan simultáneamente y la escritura de un nuevo valor espera a que finalicen las operaciones anteriores.
fuente
Use NSLock en Swift4:
fuente
En el moderno Swift 5, con capacidad de retorno:
Úselo así, para aprovechar la capacidad de valor de retorno:
O así de otra manera:
fuente
GCD). Parece que esencialmente nadie usa o entiende cómo usarThread. Estoy muy contento con eso, mientras queGCDestá lleno de problemas y limitaciones.Prueba: NSRecursiveLock
fuente
Figura Publicaré mi implementación de Swift 5, basada en las respuestas anteriores. ¡Gracias chicos! Me pareció útil tener uno que también devuelva un valor, así que tengo dos métodos.
Aquí hay una clase simple para hacer primero:
Luego úselo así si necesita un valor de retorno:
O:
fuente
public class func synced<T>(_ lock: Any, closure: () -> T), funciona para ambos, nulo y cualquier otro tipo. También está el material de rebrote.Detalles
xCode 8.3.1, swift 3.1
Tarea
Leer el valor de escritura de diferentes hilos (asíncrono).
Código
Uso
Muestra completa
fuente
Con los envoltorios de propiedades de Swift, esto es lo que estoy usando ahora:
Entonces puedes simplemente hacer:
o
Luego acceda a la variable como lo haría normalmente.
fuente
DispatchQueueque está oculto para el usuario. Encontré esta referencia SO para tranquilizarme: stackoverflow.com/a/35022486/1060314En conclusión, aquí damos una forma más común que incluye el valor de retorno o nulo, y arrojamos
fuente
¿Por qué hacerlo difícil y molesto con las cerraduras? Utilice barreras de envío.
Una barrera de despacho crea un punto de sincronización dentro de una cola concurrente.
Mientras se está ejecutando, no se permite ejecutar ningún otro bloque en la cola, incluso si es concurrente y hay otros núcleos disponibles.
Si eso suena como un bloqueo exclusivo (escritura), lo es. Los bloques sin barrera pueden considerarse bloqueos compartidos (leídos).
Siempre que todo el acceso al recurso se realice a través de la cola, las barreras proporcionan una sincronización muy barata.
fuente
Basado en ɳeuroburɳ , pruebe un caso de subclase
Salida:
fuente
dispatch_barrier_async es la mejor manera, sin bloquear el hilo actual.
dispatch_barrier_async (accessQueue, {dictionary [object.ID] = object})
fuente
Otro método es crear una superclase y luego heredarla. De esta manera puedes usar GCD más directamente
fuente