Yeg*_*sky 27 multithreading ios swift
我的应用程序需要一个读/写锁.我读过 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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
它工作得很好,直到我尝试从GCD线程使用它.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
Run Code Online (Sandbox Code Playgroud)
当我尝试在不同的异步块中使用此类时,它允许在写入被锁定时写入
这是样本日志:
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
Run Code Online (Sandbox Code Playgroud)
所以,你可以看到g被锁定了,但是objc_sync_enter(g)允许继续.为什么会这样?
顺便说一句,我检查了ReadWriteLock构建的次数,它是1.
为什么objc_sync_exit不工作,并且在没有释放时允许objc_sync_enter(g)?
PS Readwirtelock定义为
class UserData {
static let lock = ReadWriteLock()
Run Code Online (Sandbox Code Playgroud)
谢谢.
Rob*_*ier 39
objc_sync_enter是一个极低级的原语,不打算直接使用.这是@synchronizedObjC中旧系统的实现细节.即使这是非常过时的,通常应该避免.
使用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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
所有并发属性都可以共享一个队列,或者您可以为每个属性提供自己的队列.这取决于您期望的争用(作者将锁定整个队列).
"dispatch_barrier_async"中的"屏障"意味着它是当时唯一允许在队列上运行的东西,因此所有先前的读取都将完成,并且将来所有读取都将被阻止,直到它完成.这种方案意味着您可以拥有任意数量的并发读取器,而不会使编写者匮乏(因为编写器将始终处于服务状态),并且写入永远不会阻塞.读取是阻塞的,并且仅在存在实际争用时.在正常的,无争议的情况下,这非常非常快.
Ale*_*zub 19
您是否100%确定您的块实际上是在不同的线程上执行的?
objc_sync_enter()/ objc_sync_exit()只保护您从不同线程访问的对象.它们在引擎盖下使用递归互斥锁,因此它们不会死锁或阻止您重复访问同一线程中的对象.
因此,如果您锁定一个异步块并在另一个中解锁,则在中间执行的第三个块可以访问受保护对象.
Sir*_*ton 10
这是很容易错过的那些非常微妙的细微差别之一。
你必须非常小心你用作锁的东西。在 Swift 中,String是一个结构体,意味着它是传值的。
每当你打电话时objc_sync_enter(g),你不是在给它g,而是一份副本g。所以每个线程本质上都在创建自己的锁,这实际上就像根本没有锁一样。
不要使用Stringor Int,而是使用普通的NSObject。
let lock = NSObject()
func waitAndStartWriting() {
log("wait Writing")
objc_sync_enter(lock)
log("enter writing")
}
func finishWriting() {
objc_sync_exit(lock)
log("exit writing")
}
Run Code Online (Sandbox Code Playgroud)
那应该管它!
| 归档时间: |
|
| 查看次数: |
9007 次 |
| 最近记录: |