在向数组添加值时,我遇到了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)
}
}
}
}
答案 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 } }
}