concurrentPerform UnsafeMutablePointer.deinitialize 向数组添加值时出错
Posted
技术标签:
【中文标题】concurrentPerform UnsafeMutablePointer.deinitialize 向数组添加值时出错【英文标题】:concurrentPerform UnsafeMutablePointer.deinitialize error while adding value to array 【发布时间】:2017-12-24 09:12:29 【问题描述】:向数组添加值时出现并发执行错误。我按下按钮。 在错误的那一刻 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 负数 (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)
【问题讨论】:
感谢 Riajur Rahman。从这里制作 SynchronizedArray根本问题是您同时从多个线程将项目附加到数组中。 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
【讨论】:
嗨 Rob,为什么我们需要使用queue.sync
而不是 queue.async
进行读取?由于写入时带有.barrier
标志,数据不会更改,因此两者都无法工作?
这是“reader-writer”模式,其中一个确实使用屏障异步写入(调用者无需等待),但没有屏障同步读取(因为调用者可能需要该值才能继续; 这就是为什么它毕竟在阅读)。从理论上讲,您可以异步执行所有操作,但这会使调用点变得更加复杂而没有什么好处。如果不使用完成处理程序闭包或类似的东西,你就不能异步“读取”。对于一个简单的同步机制(通常非常快),上面的模式是最简单的。
现在,如果您正在同步存储可能非常慢的内容(例如,从持久存储或网络读取),那么您肯定会异步执行读取和写入操作,并且会增加复杂性。但是对于简单的读写器模式,在处理快速结构时,同步读取是最简单的。
哦,我明白了。所以原因是 API 更简单,因为我们不需要完成处理程序,而是可以直接读取值。这就说得通了。感谢您的澄清!以上是关于concurrentPerform UnsafeMutablePointer.deinitialize 向数组添加值时出错的主要内容,如果未能解决你的问题,请参考以下文章
concurrentPerform UnsafeMutablePointer.deinitialize 向数组添加值时出错
UnsafeMutableRawPointer 到 UnsafeMutablePointer<T>:指针上的 EXC_BAD_ACCESS