swift - 同时填充数组

标签 swift memory memory-management grand-central-dispatch swift5

我偶然发现了 Swift 5 中并发和数组的问题。为了重现该问题,我将代码简化为以下片段:

import Dispatch

let group = DispatchGroup()
let queue = DispatchQueue(
  label: "Concurrent threads",
  qos: .userInitiated,
  attributes: .concurrent
)

let threadCount = 4
let size = 1_000
var pixels = [SIMD3<Float>](
  repeating: .init(repeating: 0),
  count: threadCount*size
)

for thread in 0..<threadCount {
  queue.async(group: group) {
    for number in thread*size ..< (thread+1)*size {
      let floating = Float(number)
      pixels[number] = SIMD3<Float>(floating, floating, floating)
    }
  }
}

print("waiting")
group.wait()
print("Finished")

当我使用 Xcode 版本 10.2 beta 4 (10P107d) 在 Debug模式下执行此操作时,它总是崩溃并出现如下错误:

Multithread(15095,0x700008d63000) malloc: *** error for object 0x104812200: pointer being freed was not allocated
Multithread(15095,0x700008d63000) malloc: *** set a breakpoint in malloc_error_break to debug

我感觉这是编译器中的一些错误,因为当我在 Release模式下运行代码时,它运行得很好。或者我在这里做错了什么?

最佳答案

数组中的指针绝对可以在你的脚下改变。它不是原始内存。

数组不是线程安全的。数组是值类型,这意味着它们以线程安全的方式支持写时复制(因此您可以自由地将数组传递给另一个线程,如果它被复制到那里,那就可以了),但是您不能在多个线程上改变同一个数组。数组不是 C 缓冲区。它不 promise 具有连续的内存。它甚至根本没有 promise 分配内存。 Array 可以在内部选择将“我当前全为零”存储为特殊状态,并为每个下标返回 0。 (事实并非如此,但这是允许的。)

对于这个特定问题,您通常会使用 vDSP_vramp 等 vDSP 方法,但我知道这只是一个示例,可能没有可以解决该问题的 vDSP 方法。不过,通常情况下,我仍然会关注加速/SIMD 方法,而不是调度到队列。

但是如果您要分派(dispatch)到队列,则需要一个 UnsafeMutableBuffer 来控制内存(并确保内存存在):

pixels.withUnsafeMutableBufferPointer { pixelsPtr in
    DispatchQueue.concurrentPerform(iterations: threadCount) { thread in
        for number in thread*size ..< (thread+1)*size {
            let floating = Float(number)
            pixelsPtr[number] = SIMD3(floating, floating, floating)
        }
    }
}

“不安全”表示现在您的问题是确保所有访问都是合法的,并且您不会创建竞争条件。

请注意此处 .concurrentPerform 的使用。正如 @user3441734 提醒我们的那样,一旦 .withUnsafeMutablePointer 完成,pixelsPtr 并不 promise 有效。 .concurrentPerform 保证在所有 block 完成之前不会返回,因此保证指针有效。

这也可以通过 DispatchGroup 来完成,但 .wait 需要位于 withUnsafeMutableBufferPointer 内部。

关于swift - 同时填充数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53350638/

相关文章:

ios - 二元运算符 '<' 不能应用于类型 'Double?' 和 'Double' 的操作数

ios - 导航栏一旦隐藏(滑动)就不会回来

java - 调整 Tomcat 内存和 CPU 消耗

java - boolean[] 与 BitSet : Which is more efficient?

javascript - 脚本语言中变量的内存分配是如何完成的?

swift - 如何防止自定义 init 方法在 Xcode 中泄露绝对源路径?

ios - 什么时候在 Swift 中使用静态常量和变量?

java - Linux下Java的虚拟内存使用率,使用的内存过多

c++ - 转换已定义(已知)内存的邻居内存

PowerShell内存泄漏误解