Swift并发执行中的双重释放错误

问题描述 投票:0回答:1

我有以下稀疏矩阵乘以向量的代码。在稀疏矩阵中,存储每行非零元素的数量,以及该行第一个元素出现的元素数组中的索引。这些用于确保输出向量的任何元素不会被多个线程同时写入两个。在没有优化的情况下构建或在调试模式下构建时,此代码可以正常工作。然而,当我将优化级别设置为

-Ofast
时,我得到了双重免费错误。

关于我可能错过了什么有什么想法吗?

func parallelVectorMultiply(vector: Vector<T>) -> Vector<T> {
    guard space == vector.space else {
        fatalError("Number of columns in the matrix must match the size of the vector.")
    }
    
    var outputElements = [T](repeating: T(0), count: space.dimension)
    
    DispatchQueue.concurrentPerform(iterations: space.dimension) { row in
        
        let start_idx = row_first_element_offsets[row]
        if start_idx == -1 { return }
        let end_idx = start_idx + nonzero_elements_per_row[row]
        var rowSum = T(0)
        for i in start_idx..<end_idx {
            rowSum = rowSum + values[i].value * vector[values[i].col]
        }
        
        outputElements[row] = rowSum
    }
    
    return Vector(elements: outputElements, in: space)
}

我希望没有错误。在矩阵

A
乘以向量
X
的方程中:

AX = Y

地点:

$$Y_i = \sum_k A_{ik} X_k$$

在我的代码中,我计算这个总和,然后将结果存储到输出数组中的相应元素。

不应该有两个线程同时释放数组的单个元素。

swift matrix vector concurrency
1个回答
0
投票

Array
不是线程安全的。因此,
outputElements
不是线程安全的。我知道你说,“不应该有两个线程同时释放数组的单个元素”,但事实是
Array
根本就不是线程安全的。当您违反线程安全性时,您可能会表现出各种不同的问题,因此我不会详细说明您收到的任何错误/崩溃。

尝试暂时打开TSAN,可能会发现问题。 (虽然并不总是如此,但它比试图实际表现出与种族相关的问题要可靠得多。)

如果您要使用这个非线程安全的

Array
来收集结果,您必须同步对它的访问(例如,在高性能场景中,例如这样,我可能会获取锁,例如如
OSAllocatedUnfairLock
),例如:

import os.lock

还有

let lock = OSAllocatedUnfairLock()

DispatchQueue.concurrentPerform(iterations: space.dimension) { row in
    …

    lock.withLock {
        outputElements[row] = rowSum
    }
}

您还可以考虑利用已经优化了此类向量运算的库。它将使您摆脱自己进行这些低级计算的麻烦。例如,请参阅使用 vDSP 进行基于向量的算术。或者,更广泛的Accelerate框架也有各种其他选项,因此请查看文档

© www.soinside.com 2019 - 2024. All rights reserved.