gpt4 book ai didi

ios - Tidwall/安全互斥死锁

转载 作者:行者123 更新时间:2023-11-29 05:38:16 26 4
gpt4 key购买 nike

我正在使用https://github.com/tidwall/Safe ,一个 Swift 并发库,我想我发现了一个线程错误。 (我使用的是 IOS 12.3.1、iPhone Xs。Swift 4,我想;Xcode 10.2。)该库现在是只读的,所以我正在尝试自己调试它。不过,这个错误确实很微妙,或者是由我什至没有想象到的东西引起的,因为我做了与给定库几乎相同的事情,并且它工作正常,但库本身死锁了。

下面是不应该死锁的测试代码:

private func testCompetingDeadlock() {
NSLog("start")
let c = Chan<Int32>()
let b = Chan<Int32>()
let COUNT = 1000
let wg = WaitGroup()
wg.add(1)
dispatch {
NSLog("receiver starting")
for i in 0..<(2*COUNT) {
Thread.sleep(forTimeInterval: 0.01)
let v = <-c
b <- v!
}
wg.done()
}
sleep(1)
wg.add(1)
dispatch {
NSLog("sender 1 starting")
for i in 0..<COUNT {
c <- 1
<-b
NSLog("1 : \(i)")
}
NSLog("1 done")
wg.done()
}
wg.add(1)
dispatch {
NSLog("sender 2 starting")
for i in 0..<COUNT {
c <- 2
<-b
NSLog("2 : \(i)")
}
NSLog("2 done")
wg.done()
}
wg.wait()
NSLog("Both done")
}

请注意 send 的底层实现,又名<- ,是

internal func send(_ msg: T) {
NSLog("locking (\(Thread.current)) - \(Unmanaged.passUnretained(cond.mutex).toOpaque())")
cond.mutex.lock()
NSLog("locked (\(Thread.current)) - \(Unmanaged.passUnretained(cond.mutex).toOpaque())")
threadCount += 1
defer {
threadCount -= 1
NSLog("unlocking (\(Thread.current)) - \(Unmanaged.passUnretained(cond.mutex).toOpaque())")
cond.mutex.unlock()
NSLog("unlocked (\(Thread.current)) - \(Unmanaged.passUnretained(cond.mutex).toOpaque())")
}
if threadCount > 1 {
NSLog("threadCount is \(threadCount)")
}

if closed {
#if os(Linux)
assertionFailure("Send on closed channel")
#else
NSException.raise(NSExceptionName(rawValue: "Exception"), format: "send on closed channel", arguments: getVaList([]))
#endif
}
msgs.append(msg)
broadcast()
while msgs.count > cap {
cond.wait()
}
}

(我添加了日志记录,和 threadCount 。一旦发生死锁, threadCount 为 2。我在 Mutex 类中尝试了相同的“锁定后增加,解锁前减少”,我得到了 3 在死锁期间???我不知道怎么回事,我也没有进一步调查它,尽管这可能是一个重要的线索。)

如果testCompetingDeadlock运行时,死锁通常会立即发生,两个发送线程卡在cond.wait()上。线send ,都位于同一互斥体的锁定区域内。我不知道怎么办。我尝试测试 Mutex本身,就像我感知的那样 send使用它,如下:

private func testSafeMutex() {
let mutex = Mutex()

dispatch {
NSLog("1 locking")
mutex.lock()
NSLog("1 locked")
defer {
NSLog("1 unlocking")
mutex.unlock()
NSLog("1 unlocked")
}

sleep(1)
}

dispatch {
NSLog("2 locking")
mutex.lock()
NSLog("2 locked")
defer {
NSLog("2 unlocking")
mutex.unlock()
NSLog("2 unlocked")
}

sleep(1)
}
}

但是,工作正常 - 没有死锁。

我不太确定该怎么做,除了添加越来越细粒度的日志记录,并尝试合并两个测试用例,直到找到关键的差异(这会很困难,因为很难保持代码的功能版本之间)。有人可以帮我调试这个库吗?是否可能存在一些 iOS 特定的内存模型问题等?

最佳答案

我最终弄清楚了 - 我忘记了最后的 cond.wait() 释放了锁,这解释了为什么我在一个所谓的锁定部分中有多个线程。弄清楚这一点后,我找到了真正的问题并提出了解决方案:https://github.com/Erhannis/Safe/commit/cfa41231d01895457bfc1421d779a29a18923c5b

据我了解,真正的问题基本上是退出 while 循环的条件是错误的 - 所有发送线程都会等待,直到缓冲区有空间,但那些消息已被发送的线程read 应该在读取消息后退出循环。

关于ios - Tidwall/安全互斥死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56812006/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com