concurrentPerform在向数组添加值时出现UnsafeMutablePointer.deinitialize错误

时间:2017-12-24 09:12:30

标签: ios grand-central-dispatch

在向数组添加值时,我遇到了concurrentPerform错误。我按下按钮。 在出错的那一刻,myArray01有133个。在其他运行中,myArray01有69个元素。如何删除此错误?

错误行

  

主题8:EXC_BAD_INSTRUCTION(代码= EXC_I386_INVOP,子代码= 0x0)

在控制台

  

致命错误:带有负数的UnsafeMutablePointer.deinitialize   2017-12-24 11:59:53.438933 + 0300 ap02 [7624:1873749]致命错误:   UnsafeMutablePointer.deinitialize with negative count(lldb)

类似的话题 Swift:UnsafeMutablePointer.deinitialize在附加到数组时带有负数的致命错误 Swift: UnsafeMutablePointer.deinitialize fatal error with negative count when appending to array

var myArray01 = [4444,5555]

@IBAction func button01Pressed(_ sender: Any) {
    self.doIt01()
}

func doIt01() {
    DispatchQueue.concurrentPerform(iterations: 1000) { iter in
        var max = 100000
        for iterB in 0..<100000 {
            var k = 0
            k = k + 1
            var half:Int = max/2
            if (iterB == half) {
                myArray01.append(iter)
            }
        }
    }
}

1 个答案:

答案 0 :(得分:5)

基本问题是您要同时从多个线程向数组追加项。 Swift Array类型不是线程安全的。您必须synchronize与之互动。例如,您可以使用串行队列自行同步:

DispatchQueue.global().async {
    let queue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".synchronization")

    var array = [4444,5555]

    DispatchQueue.concurrentPerform(iterations: 1000) { iter in
        var max = 100_000
        for iterB in 0 ..< 100_000 {
            var k = 0
            k = k + 1
            var half = max/2
            if iterB == half {
                queue.async {
                    array.append(iter)
                }
            }
        }
    }

    queue.async {
        print(array)
    }
}

注意,我还建议将concurrentPerform分派给后台线程,因为它在并行运行代码时会阻塞当前线程,直到完成所有这些并行循环。

或者您可以使用为您执行同步的数组类型:

DispatchQueue.global().async {
    let array = SynchronizedArray(array: [4444,5555])

    DispatchQueue.concurrentPerform(iterations: 1000) { iter in
        let max = 100_000
        for iterB in 0 ..< 100_000 {
            var k = 0
            k = k + 1
            let half = max/2
            if iterB == half {
                array.append(iter)
            }
        }
    }

    print(array)
}

其中

//
//  SynchronizedArray.swift
//
//  Created by Robert Ryan on 12/24/17.
//

import Foundation

/// A synchronized, ordered, random-access array.
///
/// This provides low-level synchronization for an array, employing the
/// reader-writer pattern (using concurrent queue, allowing concurrent
/// "reads" but using barrier to ensure nothing happens concurrently with
/// respect to "writes".
///
/// - Note: This may not be sufficient to achieve thread-safety,
///         as that is often only achieved with higher-level synchronization.
///         But for many situations, this can be sufficient.

final class SynchronizedArray<Element> {
    private var array: [Element]
    private let queue: DispatchQueue

    init(array: [Element] = [], qos: DispatchQoS = .default) {
        self.array = array
        self.queue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".synchronization", qos: qos, attributes: .concurrent)
    }

    /// First element in the collection.

    var first: Element? {
        return queue.sync { self.array.first }
    }

    /// Last element in the collection.

    var last: Element? {
        return queue.sync { self.array.last }
    }

    /// The number of elements in the collection.

    var count: Int {
        return queue.sync { self.array.count }
    }

    /// Inserts new element at the specified position.
    ///
    /// - Parameters:
    ///   - newElement: The element to be inserted.
    ///   - index: The position at which the element should be inserted.

    func insert(_ newElement: Element, at index: Int) {
        queue.async(flags: .barrier) {
            self.array.insert(newElement, at: index)
        }
    }

    /// Appends new element at the end of the collection.
    ///
    /// - Parameter newElement: The element to be appended.

    func append(_ newElement: Element) {
        queue.async(flags: .barrier) {
            self.array.append(newElement)
        }
    }

    /// Removes all elements from the array.

    func removeAll() {
        queue.async(flags: .barrier) {
            self.array.removeAll()
        }
    }

    /// Remove specific element from the array.
    ///
    /// - Parameter index: The position of the element to be removed.

    func remove(at index: Int) {
        queue.async(flags: .barrier) {
            self.array.remove(at: index)
        }
    }

    /// Retrieve or update the element at a particular position in the array.
    ///
    /// - Parameter index: The position of the element.

    subscript(index: Int) -> Element {
        get {
            return queue.sync { self.array[index] }
        }
        set {
            queue.async(flags: .barrier) { self.array[index] = newValue }
        }
    }

    /// Perform a writer block of code asynchronously within the synchronization system for this array.
    ///
    /// This is used for performing updates, where no result is returned. This is the "writer" in
    /// the "reader-writer" pattern, which performs the block asynchronously with a barrier.
    ///
    /// For example, the following checks to see if the array has one or more values, and if so,
    /// remove the first item:
    ///
    ///     synchronizedArray.writer { array in
    ///         if array.count > 0 {
    ///             array.remove(at: 0)
    ///         }
    ///     }
    ///
    /// In this example, we use the `writer` method to avoid race conditions between checking
    /// the number of items in the array and the removing of the first item.
    ///
    /// If you are not performing updates to the array itself or its values, it is more efficient
    /// to use the `reader` method.
    ///
    /// - Parameter block: The block to be performed. This is allowed to mutate the array. This is
    ///                    run on a private synchronization queue using a background thread.

    func writer(with block: @escaping (inout [Element]) -> Void) {
        queue.async(flags: .barrier) {
            block(&self.array)
        }
    }

    /// Perform a "reader" block of code within the synchronization system for this array.
    ///
    /// This is the "reader" in the "reader-writer" pattern. This performs the read synchronously,
    /// potentially concurrently with other "readers", but never concurrently with any "writers".
    ///
    /// This is used for reading and performing calculations on the array, where a whole block of
    /// code needs to be synchronized. The block may, optionally, return a value.
    /// This should not be used for performing updates on the array itself. To do updates,
    /// use `writer` method.
    ///
    /// For example, if dealing with array of integers, you could average them with:
    ///
    ///     let average = synchronizedArray.reader { array -> Double in
    ///         let count = array.count
    ///         let sum = array.reduce(0, +)
    ///         return Double(sum) / Double(count)
    ///     }
    ///
    /// This example ensures that there is no race condition between the checking of the
    /// number of items in the array and the calculation of the sum of the values.
    ///
    /// - Parameter block: The block to be performed. This is not allowed to mutate the array.
    ///                    This runs on a private synchronization queue (so if you need main queue,
    ///                    you will have to dispatch that yourself).

    func reader<U>(block: ([Element]) -> U) -> U {
        return queue.sync {
            block(self.array)
        }
    }

    /// Retrieve the array for use elsewhere.
    ///
    /// This resulting array is a copy of the underlying `Array` used by `SynchronizedArray`.
    /// This copy will not participate in any further synchronization.

    var copy: [Element] { return queue.sync { self.array } }
}

extension SynchronizedArray: CustomStringConvertible {
    // Use the description of the underlying array

    var description: String { return queue.sync { self.array.description } }
}