ios - 对于数组的本地副本,Swift Array 排序方法线程安全吗?
问题描述
我的应用程序在下面第 2 行的排序过程中遇到了崩溃。这发生在一个方法中,ViewController
当 aNSNotification
进入以触发排序并刷新显示时。
我的理解是,第devices
1 行的数组是从字典创建的新数组,因此即使字典可能会更改,访问元素也是安全的。
即使serialID
(a String?
) 在排序过程中发生变化,我也不认为这会导致崩溃。
我错过了什么?什么可能导致排序内部的错误访问?
1: var devices = deviceDict.valuesArray() // See Edit below
2: let sortedDevices = devices.sorted(by: { ($0.serialID ?? "") < ($1.serialID ?? "") })
我没有已知的方法来重现这个。我只在下面的崩溃报告中看到过它。
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000f9a70f7c0
VM Region Info: 0xf9a70f7c0 is not in any region. Bytes after previous region: 55741315009 Bytes before following region: 630130752
REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL
MALLOC_NANO 280000000-2a0000000 [512.0M] rw-/rwx SM=COW
---> GAP OF 0xd20000000 BYTES
commpage (reserved) fc0000000-1000000000 [ 1.0G] ---/--- SM=NUL ...(unallocated)
Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL, Code 0xb
Terminating Process: exc handler [4510]
Triggered by Thread: 9
...
Thread 9 Crashed:
0 libobjc.A.dylib 0x00000001a6ae2dd0 objc_release + 16 (objc-runtime-new.h:1589)
1 OAPP 0x00000001044c35e4 specialized UnsafeMutableBufferPointer._stableSortImpl(by:) + 364 (DeviceViewController.swift:0)
2 OAPP 0x00000001044c17f0 specialized MutableCollection<>.sort(by:) + 100
2 OAPP 0x00000001044baf60 DeviceViewController.generateDeviceList() + 1644
4 OAPP 0x00000001044b67ac DeviceViewController.refreshDeviceTableView() + 524 (DeviceViewController.swift:655)
5 OAPP 0x00000001044bb7a4 DeviceViewController.handleSyncStateNotification(_:) + 680 (DeviceViewController.swift:821)
...
编辑:deviceDict
实际上是在一个自定义类上,该类包装了一些线程安全访问器的字典,我将字典值转换为该类中的数组。(在我原来的帖子中,我试图简化代码,以免分散对数组操作的崩溃问题的注意力,但我似乎因为简化而混淆了事情。对不起!)
public class SafeDict<Element> {
fileprivate let queue = DispatchQueue(label: "com.myapp.SafeDict", attributes: .concurrent)
fileprivate var dictionary:[String:Element] = [:]
...
public func valuesSafe() -> Dictionary<String, Element>.Values {
var returnValues: Dictionary<String, Element>.Values = Dictionary<String, Element>().values
queue.sync {
returnValues = self.dictionary.values
}
return returnValues
}
public func valuesArray() -> [Element] {
var values: [Element] = []
queue.sync {
for element in self.valuesSafe() {
values.append(element)
}
}
return values
}
}
解决方案
devices
不是数组。这是一个Dictionary.Values
。这是对 deviceDict 的惰性视图。
但这些都不重要。在多个线程上对 deviceDict 的可变访问始终是未定义的行为。如果可以serialID
在没有某种同步的情况下在另一个线程上进行更改,那么您已经犯了一个错误。该deviceDict.values()
行将无效;与以后访问它无关。
但当然,这sorted
条线更有可能是那种未定义的行为咬你的地方,因为它会遍历很多值,如果deviceDict
必须调整大小或以其他方式修改其后备存储,这些值可能会在内存中移动。
推荐阅读
- reactjs - 等待和检查元素不会出现
- reactjs - 单击按钮时如何在传奇函数上运行调度?
- sql - 将 SQL 查询转换为 TypeORM 查询构建器代码
- html - 我试图使用 ionic 在 android 手机中设置壁纸
- r - LIME 和解释中的理解系数
- r - 检查一个数据框列中的值是否存在于R中的第二个数据框(带边界)中
- python - 批量插入/合并节点和边的正确方法
- google-analytics - 谷歌优化数据每天都在清除
- javascript - 带有 Express(JS) 的后端 - GraphQL 变异函数不起作用
- javascript - React Jest Dynamodb 测试结果错误:原因:方法不允许