objc_sync_enter / objc_sync_exit不适用于DISPATCH_QUEUE_PRIORITY_LOW

我需要一个读/写locking我的应用程序。 我读过https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock

并写了我自己的类,因为没有快速读/写锁

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

它运作良好,直到我尝试从GCD线程使用它。

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

当我尝试从不同的asynchronous块在某个时刻使用这个类时,它允许在写入locking时写入

这里是样本日志:

 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 

所以,你可以看到g被locking,但objc_sync_enter(g)允许继续。 为什么会发生?

顺便说一句,我检查了多less次ReadWriteLock构造,它是1。

为什么objc_sync_exit不工作,并允许objc_sync_enter(g),当它没有被释放?

PS Readwirtelock定义为

 class UserData { static let lock = ReadWriteLock() 

谢谢。

objc_sync_enter是一个非常低级的基元,不能直接使用。 这是ObjC中旧的@synchronized系统的实现细节。 即使这已经过时了,通常应该避免。

Cocoa中的同步访问最好通过GCD队列来实现。 例如,这是实现读写器locking(并发读取,专有写入)的常用方法。

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

所有的并发属性都可以共享一个队列,也可以给每个属性分配一个队列。 这取决于你期望多less争用(一个作者将locking整个队列)。

“dispatch_barrier_async”中的“障碍”意味着它是当时允许在队列中运行的唯一的东西,因此所有以前的读取将会完成,并且所有未来的读取将被阻止直到它完成。 这个scheme意味着你可以拥有尽可能多的并发阅读器,而不需要编写器(因为编写器将总是被服务),并且写入永远不会被阻塞。 读取是阻塞的,只有当实际的争用。 在正常的,没有争议的情况下,这是非常非常快的。

你是否100%确定你的块实际上在不同的线程上执行?

objc_sync_enter() / objc_sync_exit()只保护你从不同线程访问的对象。 他们在引擎盖下使用recursion互斥,所以它们不会死锁,也不会阻止你从同一个线程中重复访问对象。

因此,如果您locking一个asynchronous块并在另一个asynchronous块中解锁,则在中间执行的第三个块可以访问守护对象。