objc_sync_enter / objc_sync_exit no funciona con DISPATCH_QUEUE_PRIORITY_LOW

Necesito un locking de lectura \ escritura para mi aplicación. He leído https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock

y escribí mi propia class, porque no hay locking de lectura / escritura en swift

class ReadWriteLock { var logging = true var b = 0 let r = "vdsbsdbs" // string1 for locking let g = "VSDBVSDBSDBNSDN" // string2 for locking func waitAndStartWriting() { log("wait Writing") objc_sync_enter(g) log("enter writing") } func finishWriting() { objc_sync_exit(g) log("exit writing") } // ждет пока все чтение завершится чтобы начать чтение // и захватить мютекс func waitAndStartReading() { log("wait reading") objc_sync_enter(r) log("enter reading") b++ if b == 1 { objc_sync_enter(g) log("read lock writing") } print("b = \(b)") objc_sync_exit(r) } func finishReading() { objc_sync_enter(r) b-- if b == 0 { objc_sync_exit(g) log("read unlock writing") } print("b = \(b)") objc_sync_exit(r) } private func log(s: String) { if logging { print(s) } } } 

Funciona bien, hasta que bash usarlo de los hilos GCD.

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0) dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 

Cuando bash usar esta class desde diferentes bloques asíncronos en algún momento, permite escribir cuando la escritura está bloqueada

aquí está el logging de muestra:

 wait reading enter reading read lock writing b = 1 wait reading enter reading b = 2 wait reading enter reading b = 3 wait reading enter reading b = 4 wait reading enter reading b = 5 wait reading enter reading b = 6 wait reading enter reading b = 7 wait reading enter reading b = 8 wait reading enter reading b = 9 b = 8 b = 7 b = 6 b = 5 wait Writing enter writing exit writing wait Writing enter writing 

Entonces, como puedes ver, g estaba bloqueado, pero objc_sync_enter (g) permite continuar. ¿Por qué podría suceder esto?

BTW comprobé cuántas veces se construyó ReadWriteLock, y es 1.

¿Por qué objc_sync_exit no funciona y permite objc_sync_enter (g) cuando no se libera?

PS Readwirtelock definido como

 class UserData { static let lock = ReadWriteLock() 

Gracias.

objc_sync_enter es una primitiva de nivel extremadamente bajo y no está destinada a utilizarse directamente. Es un detalle de implementación del viejo sistema @synchronized en ObjC. Incluso eso es extremadamente anticuado y generalmente debe evitarse.

El acceso sincronizado en el cocoa se logra mejor con las queues GCD. Por ejemplo, este es un enfoque común que logra un locking lector / escritor (lectura simultánea, escritura exclusiva).

 public class UserData { private let myPropertyQueue = dispatch_queue_create("com.example.mygreatapp.property", DISPATCH_QUEUE_CONCURRENT) private var _myProperty = "" // Backing storage public var myProperty: String { get { var result = "" dispatch_sync(myPropertyQueue) { result = self._myProperty } return result } set { dispatch_barrier_async(myPropertyQueue) { self._myProperty = newValue } } } } 

Todas sus properties simultáneas pueden compartir una sola queue, o puede otorgarle a cada propiedad su propia queue. Depende de la cantidad de contención que espere (un escritor bloqueará toda la queue).

La "barrera" en "dispatch_barrier_async" significa que es lo único que se puede ejecutar en la queue en ese momento, por lo que todas las lecturas anteriores se habrán completado, y todas las lecturas futuras se evitarán hasta que se complete. Este esquema significa que puede tener tantos lectores simultáneos como desee sin escritores hambrientos (ya que los escritores siempre serán revisados), y las escrituras nunca estarán bloqueando. Las lecturas están bloqueando, y solo si hay contienda real. En el caso normal, no controvertido, esto es extremadamente rápido.

¿Estás 100% seguro de que tus bloques realmente se están ejecutando en diferentes subprocesss?

objc_sync_enter() / objc_sync_exit() están protegiendo solo del object al que se accede desde diferentes subprocesss. Utilizan un mutex recursivo debajo del capó, por lo que no bloquearán ni impedirán que accedan repetidamente al object desde el mismo hilo.

Entonces, si se bloquea en un bloque asíncrono y se desbloquea en otro, el tercer bloque ejecutado en el medio puede tener acceso al object protegido.