我需要为我的应用程序读/写锁。我已阅读 https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock
并写了我自己的类,因为在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) } } }
效果很好,直到我尝试从GCD线程使用它。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0) dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
当我尝试在某个时刻从不同的异步块使用此类时,它允许在写入被锁定时进行写入
这是示例日志:
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被锁定,但是objc_sync_enter(g)允许继续。为什么会发生这种情况?
顺便说一句,我检查了构造ReadWriteLock的次数,它是1。
为什么objc_sync_exit不能正常工作,并在未释放objc_sync_enter(g)时允许呢?
PS Readwirtelock定义为
class UserData { static let lock = ReadWriteLock()
谢谢。
objc_sync_enter是一个非常低级的原语,不能直接使用。这是@synchronizedObjC中旧系统的实现细节。即使那是非常过时的,通常也应该避免。
objc_sync_enter
@synchronized
使用GCD队列可以最好地实现Cocoa中的同步访问。例如,这是一种实现读取器/写入器锁定(并行读取,互斥写入)的常用方法。
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 } } } }
您的所有并发属性可以共享一个队列,也可以为每个属性分配自己的队列。这取决于您期望多少争用(作家将锁定整个队列)。
“ dispatch_barrier_async”中的“屏障”意味着它是当时唯一允许在队列上运行的事物,因此所有先前的读取将已完成,并且所有将来的读取将被阻止,直到完成为止。这种方案意味着您可以拥有任意数量的并发读取器,而不会饿死写入器(因为将始终为写入器提供服务),并且写入从不阻塞。仅当存在实际争用时,读取才被阻止。在正常情况下,这是非常快的。