在 Swift 中创建线程安全数组

我在 Swift 里有个线程问题。我有一个包含一些对象的数组。通过一个委托,该类几乎每秒钟都会获得一个新对象。之后,我必须检查对象是否已经在数组中,所以我必须更新对象,否则我必须删除/添加新对象。

如果我添加一个新对象,我必须首先通过网络获取一些数据。这是通过一块手柄。

现在我的问题是,如何同步这些任务?

我已经尝试使用了  传递 _ 信号量,但是这个信号量阻塞了 UI,直到阻塞完成为止。

我还尝试了一个简单的 bool 变量,它检查块是否当前执行,同时跳过比较方法。

但这两种方法都不理想。

管理数组的最佳方法是什么? 我不希望数组中有重复的数据。

72687 次浏览

我解决这个问题的方法是使用串行调度队列来同步对盒装数组的访问。当您尝试获取 index 上的值时,它会阻塞线程,队列非常忙,但这也是锁的问题所在。

public class SynchronizedArray<T> {
private var array: [T] = []
private let accessQueue = dispatch_queue_create("SynchronizedArrayAccess", DISPATCH_QUEUE_SERIAL)


public func append(newElement: T) {
dispatch_async(self.accessQueue) {
self.array.append(newElement)
}
}


public subscript(index: Int) -> T {
set {
dispatch_async(self.accessQueue) {
self.array[index] = newValue
}
}
get {
var element: T!


dispatch_sync(self.accessQueue) {
element = self.array[index]
}


return element
}
}
}


var a = SynchronizedArray<Int>()
a.append(1)
a.append(2)
a.append(3)


// can be empty as this is non-thread safe access
println(a.array)


// thread-safe synchonized access
println(a[0])
println(a[1])
println(a[2])

给斯威夫特的最新消息

推荐的线程安全访问模式是使用分派 barrier:

let queue = DispatchQueue(label: "thread-safe-obj", attributes: .concurrent)


// write
queue.async(flags: .barrier) {
// perform writes on data
}


// read
var value: ValueType!
queue.sync {
// perform read and assign value
}
return value

我认为调度障碍值得研究。对我来说,使用 gcd 实现同步性比使用 sync 关键字避免多个线程的状态变化更直观。

Https://mikeash.com/pyblog/friday-qa-2011-10-14-whats-new-in-gcd.html

一个小细节: 在 Swift 3中(至少在 Xcode 8 Beta 6中) ,队列的语法发生了显著变化。对于@Kirstein 的回答,重要的变化是:

private let accessQueue = DispatchQueue(label: "SynchronizedArrayAccess")


txAccessQueue.async() {
// Your async code goes here...
}


txAccessQueue.sync() {
// Your sync code goes here...
}

这里有一个很好的答案,它是线程安全的,不会阻塞并发读操作: https://stackoverflow.com/a/15936959/2050665

它是用 Objective C 编写的,但是移植到 Swift 是微不足道的。

@property (nonatomic, readwrite, strong) dispatch_queue_t thingQueue;
@property (nonatomic, strong) NSObject *thing;


- (id)init {
...
_thingQueue = dispatch_queue_create("...", DISPATCH_QUEUE_CONCURRENT);
...
}


- (NSObject *)thing {
__block NSObject *thing;
dispatch_sync(self.thingQueue, ^{
thing = _thing;
});
return thing;
}


- (void)setThing:(NSObject *)thing {
dispatch_barrier_async(self.thingQueue, ^{
_thing = thing;
});
}

归功于 https://stackoverflow.com/users/97337/rob-napier

Kirsteins 的答案是正确的,但为了方便起见,我用 Amol Chaudhari 和 Rob 的建议更新了这个答案,他们建议使用具有异步屏障的并发队列来允许并发读取,但是阻塞写入。

我还包装了其他一些对我有用的数组函数。

public class SynchronizedArray<T> {
private var array: [T] = []
private let accessQueue = dispatch_queue_create("SynchronizedArrayAccess", DISPATCH_QUEUE_CONCURRENT)


public func append(newElement: T) {
dispatch_barrier_async(self.accessQueue) {
self.array.append(newElement)
}
}


public func removeAtIndex(index: Int) {
dispatch_barrier_async(self.accessQueue) {
self.array.removeAtIndex(index)
}
}


public var count: Int {
var count = 0


dispatch_sync(self.accessQueue) {
count = self.array.count
}


return count
}


public func first() -> T? {
var element: T?


dispatch_sync(self.accessQueue) {
if !self.array.isEmpty {
element = self.array[0]
}
}


return element
}


public subscript(index: Int) -> T {
set {
dispatch_barrier_async(self.accessQueue) {
self.array[index] = newValue
}
}
get {
var element: T!


dispatch_sync(self.accessQueue) {
element = self.array[index]
}


return element
}
}
}

更新 这是相同的代码,为 Swift3更新。

public class SynchronizedArray<T> {
private var array: [T] = []
private let accessQueue = DispatchQueue(label: "SynchronizedArrayAccess", attributes: .concurrent)


public func append(newElement: T) {


self.accessQueue.async(flags:.barrier) {
self.array.append(newElement)
}
}


public func removeAtIndex(index: Int) {


self.accessQueue.async(flags:.barrier) {
self.array.remove(at: index)
}
}


public var count: Int {
var count = 0


self.accessQueue.sync {
count = self.array.count
}


return count
}


public func first() -> T? {
var element: T?


self.accessQueue.sync {
if !self.array.isEmpty {
element = self.array[0]
}
}


return element
}


public subscript(index: Int) -> T {
set {
self.accessQueue.async(flags:.barrier) {
self.array[index] = newValue
}
}
get {
var element: T!
self.accessQueue.sync {
element = self.array[index]
}


return element
}
}
}

方法:

使用 DispatchQueue进行同步

参考:

Http://basememara.com/creating-thread-safe-arrays-in-swift/

密码:

下面是一个线程安全数组的粗略实现,您可以对它进行微调。

public class ThreadSafeArray<Element> {
    

private var elements    : [Element]
private let syncQueue   = DispatchQueue(label: "Sync Queue",
qos: .default,
attributes: .concurrent,
autoreleaseFrequency: .inherit,
target: nil)
    

public init() {
elements = []
}
    

public init(_ newElements: [Element]) {
elements = newElements
}
    

//MARK: Non-mutating
    

public var first : Element? {
return syncQueue.sync {
elements.first
}
}
    

public var last : Element? {
return syncQueue.sync {
elements.last
}
}
    

public var count : Int {
        

return syncQueue.sync {
elements.count
}
}
    

public subscript(index: Int) -> Element {
        

get {
return syncQueue.sync {
elements[index]
}
}
        

set {
syncQueue.sync(flags: .barrier) {
elements[index] = newValue
}
}
}
    

public func reversed() -> [Element] {
        

return syncQueue.sync {
        

elements.reversed()
}
}
    

public func flatMap<T>(_ transform: (Element) throws -> T?) rethrows -> [T]  {
        

return try syncQueue.sync {
        

try elements.flatMap(transform)
}
}
    

public func filter(_ isIncluded: (Element) -> Bool) -> [Element] {
        

return syncQueue.sync {
         

elements.filter(isIncluded)
}
}
    

//MARK: Mutating
    

public func append(_ element: Element) {
    

syncQueue.sync(flags: .barrier) {
            

elements.append(element)
}
}
    

public func append<S>(contentsOf newElements: S) where Element == S.Element, S : Sequence {
        

syncQueue.sync(flags: .barrier) {
            

elements.append(contentsOf: newElements)
}
}
    

public func remove(at index: Int) -> Element? {


var element : Element?


syncQueue.sync(flags: .barrier) {
            

if elements.startIndex ..< elements.endIndex ~= index {
element = elements.remove(at: index)
}
else {
element = nil
}
}
        

return element
}
}


extension ThreadSafeArray where Element : Equatable {
    

public func index(of element: Element) -> Int? {
        

return syncQueue.sync {
elements.index(of: element)
}
}
}

首先,objecc _ sync _ enter 不起作用

objc_sync_enter(array)
defer {
objc_sync_exit(array)
}

原因 Objecc _ sync _ enter/objecc _ sync _ exit 不能与 DISPATCH _ QUEUE _ PRIORITY _ LOW 一起工作

Objecc _ sync _ enter 是一个非常低级的原语,不打算直接使用。它是 OBC 中旧的@sync 系统的一个实现细节。

就像@Kirstein 说的,我建议用同步代替异步:

private let syncQueue = DispatchQueue(label:"com.test.LockQueue")
func test(){
self.syncQueue.sync{
// thread safe code here
}
}

细节

  • Xcode 10.1(10B61) ,Swift 4.2
  • Xcode 10.2.1(10E1001) ,Swift 5

解决方案

import Foundation


// https://developer.apple.com/documentation/swift/rangereplaceablecollection
struct AtomicArray<T>: RangeReplaceableCollection {


typealias Element = T
typealias Index = Int
typealias SubSequence = AtomicArray<T>
typealias Indices = Range<Int>
fileprivate var array: Array<T>
var startIndex: Int { return array.startIndex }
var endIndex: Int { return array.endIndex }
var indices: Range<Int> { return array.indices }


func index(after i: Int) -> Int { return array.index(after: i) }


private var semaphore = DispatchSemaphore(value: 1)
fileprivate func _wait() { semaphore.wait() }
fileprivate func _signal() { semaphore.signal() }
}


// MARK: - Instance Methods


extension AtomicArray {


init<S>(_ elements: S) where S : Sequence, AtomicArray.Element == S.Element {
array = Array<S.Element>(elements)
}


init() { self.init([]) }


init(repeating repeatedValue: AtomicArray.Element, count: Int) {
let array = Array(repeating: repeatedValue, count: count)
self.init(array)
}
}


// MARK: - Instance Methods


extension AtomicArray {


public mutating func append(_ newElement: AtomicArray.Element) {
_wait(); defer { _signal() }
array.append(newElement)
}


public mutating func append<S>(contentsOf newElements: S) where S : Sequence, AtomicArray.Element == S.Element {
_wait(); defer { _signal() }
array.append(contentsOf: newElements)
}


func filter(_ isIncluded: (AtomicArray.Element) throws -> Bool) rethrows -> AtomicArray {
_wait(); defer { _signal() }
let subArray = try array.filter(isIncluded)
return AtomicArray(subArray)
}


public mutating func insert(_ newElement: AtomicArray.Element, at i: AtomicArray.Index) {
_wait(); defer { _signal() }
array.insert(newElement, at: i)
}


mutating func insert<S>(contentsOf newElements: S, at i: AtomicArray.Index) where S : Collection, AtomicArray.Element == S.Element {
_wait(); defer { _signal() }
array.insert(contentsOf: newElements, at: i)
}


mutating func popLast() -> AtomicArray.Element? {
_wait(); defer { _signal() }
return array.popLast()
}


@discardableResult mutating func remove(at i: AtomicArray.Index) -> AtomicArray.Element {
_wait(); defer { _signal() }
return array.remove(at: i)
}


mutating func removeAll() {
_wait(); defer { _signal() }
array.removeAll()
}


mutating func removeAll(keepingCapacity keepCapacity: Bool) {
_wait(); defer { _signal() }
array.removeAll()
}


mutating func removeAll(where shouldBeRemoved: (AtomicArray.Element) throws -> Bool) rethrows {
_wait(); defer { _signal() }
try array.removeAll(where: shouldBeRemoved)
}


@discardableResult mutating func removeFirst() -> AtomicArray.Element {
_wait(); defer { _signal() }
return array.removeFirst()
}


mutating func removeFirst(_ k: Int) {
_wait(); defer { _signal() }
array.removeFirst(k)
}


@discardableResult mutating func removeLast() -> AtomicArray.Element {
_wait(); defer { _signal() }
return array.removeLast()
}


mutating func removeLast(_ k: Int) {
_wait(); defer { _signal() }
array.removeLast(k)
}


@inlinable public func forEach(_ body: (Element) throws -> Void) rethrows {
_wait(); defer { _signal() }
try array.forEach(body)
}


mutating func removeFirstIfExist(where shouldBeRemoved: (AtomicArray.Element) throws -> Bool) {
_wait(); defer { _signal() }
guard let index = try? array.firstIndex(where: shouldBeRemoved) else { return }
array.remove(at: index)
}


mutating func removeSubrange(_ bounds: Range<Int>) {
_wait(); defer { _signal() }
array.removeSubrange(bounds)
}


mutating func replaceSubrange<C, R>(_ subrange: R, with newElements: C) where C : Collection, R : RangeExpression, T == C.Element, AtomicArray<Element>.Index == R.Bound {
_wait(); defer { _signal() }
array.replaceSubrange(subrange, with: newElements)
}


mutating func reserveCapacity(_ n: Int) {
_wait(); defer { _signal() }
array.reserveCapacity(n)
}


public var count: Int {
_wait(); defer { _signal() }
return array.count
}


public var isEmpty: Bool {
_wait(); defer { _signal() }
return array.isEmpty
}
}


// MARK: - Get/Set


extension AtomicArray {


// Single  action


func get() -> [T] {
_wait(); defer { _signal() }
return array
}


mutating func set(array: [T]) {
_wait(); defer { _signal() }
self.array = array
}


// Multy actions


mutating func get(closure: ([T])->()) {
_wait(); defer { _signal() }
closure(array)
}


mutating func set(closure: ([T]) -> ([T])) {
_wait(); defer { _signal() }
array = closure(array)
}
}


// MARK: - Subscripts


extension AtomicArray {


subscript(bounds: Range<AtomicArray.Index>) -> AtomicArray.SubSequence {
get {
_wait(); defer { _signal() }
return AtomicArray(array[bounds])
}
}


subscript(bounds: AtomicArray.Index) -> AtomicArray.Element {
get {
_wait(); defer { _signal() }
return array[bounds]
}
set(value) {
_wait(); defer { _signal() }
array[bounds] = value
}
}
}


// MARK: - Operator Functions


extension AtomicArray {


static func + <Other>(lhs: Other, rhs: AtomicArray) -> AtomicArray where Other : Sequence, AtomicArray.Element == Other.Element {
return AtomicArray(lhs + rhs.get())
}


static func + <Other>(lhs: AtomicArray, rhs: Other) -> AtomicArray where Other : Sequence, AtomicArray.Element == Other.Element {
return AtomicArray(lhs.get() + rhs)
}


static func + <Other>(lhs: AtomicArray, rhs: Other) -> AtomicArray where Other : RangeReplaceableCollection, AtomicArray.Element == Other.Element {
return AtomicArray(lhs.get() + rhs)
}


static func + (lhs: AtomicArray<Element>, rhs: AtomicArray<Element>) -> AtomicArray {
return AtomicArray(lhs.get() + rhs.get())
}


static func += <Other>(lhs: inout AtomicArray, rhs: Other) where Other : Sequence, AtomicArray.Element == Other.Element {
lhs._wait(); defer { lhs._signal() }
lhs.array += rhs
}
}


// MARK: - CustomStringConvertible


extension AtomicArray: CustomStringConvertible {
var description: String {
_wait(); defer { _signal() }
return "\(array)"
}
}


// MARK: - Equatable


extension AtomicArray where Element : Equatable {


func split(separator: Element, maxSplits: Int, omittingEmptySubsequences: Bool) -> [ArraySlice<Element>] {
_wait(); defer { _signal() }
return array.split(separator: separator, maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences)
}


func firstIndex(of element: Element) -> Int? {
_wait(); defer { _signal() }
return array.firstIndex(of: element)
}


func lastIndex(of element: Element) -> Int? {
_wait(); defer { _signal() }
return array.lastIndex(of: element)
}


func starts<PossiblePrefix>(with possiblePrefix: PossiblePrefix) -> Bool where PossiblePrefix : Sequence, Element == PossiblePrefix.Element {
_wait(); defer { _signal() }
return array.starts(with: possiblePrefix)
}


func elementsEqual<OtherSequence>(_ other: OtherSequence) -> Bool where OtherSequence : Sequence, Element == OtherSequence.Element {
_wait(); defer { _signal() }
return array.elementsEqual(other)
}


func contains(_ element: Element) -> Bool {
_wait(); defer { _signal() }
return array.contains(element)
}


static func != (lhs: AtomicArray<Element>, rhs: AtomicArray<Element>) -> Bool {
lhs._wait(); defer { lhs._signal() }
rhs._wait(); defer { rhs._signal() }
return lhs.array != rhs.array
}


static func == (lhs: AtomicArray<Element>, rhs: AtomicArray<Element>) -> Bool {
lhs._wait(); defer { lhs._signal() }
rhs._wait(); defer { rhs._signal() }
return lhs.array == rhs.array
}
}

用法示例1

import Foundation


// init
var array = AtomicArray<Int>()
print(array)
array = AtomicArray(repeating: 0, count: 5)
print(array)
array = AtomicArray([1,2,3,4,5,6,7,8,9])
print(array)


// add
array.append(0)
print(array)
array.append(contentsOf: [5,5,5])
print(array)


// filter
array = array.filter { $0 < 7 }
print(array)


// map
let strings = array.map { "\($0)" }
print(strings)


// insert
array.insert(99, at: 5)
print(array)
array.insert(contentsOf: [2, 2, 2], at: 0)
print(array)


// pop
_ = array.popLast()
print(array)
_ = array.popFirst()
print(array)


// remove
array.removeFirst()
print(array)
array.removeFirst(3)
print(array)
array.remove(at: 2)
print(array)
array.removeLast()
print(array)
array.removeLast(5)
print(array)
array.removeAll { $0%2 == 0 }
print(array)
array = AtomicArray([1,2,3,4,5,6,7,8,9,0])
array.removeSubrange(0...2)
print(array)
array.replaceSubrange(0...2, with: [0,0,0])
print(array)
array.removeAll()
print(array)


array.set(array: [1,2,3,4,5,6,7,8,9,0])
print(array)


// subscript
print(array[0])
array[0] = 100
print(array)
print(array[1...4])


// operator functions
array = [1,2,3] + AtomicArray([4,5,6])
print(array)
array = AtomicArray([4,5,6]) + [1,2,3]
print(array)
array = AtomicArray([1,2,3]) + AtomicArray([4,5,6])
print(array)

用法示例2

import Foundation


var arr = AtomicArray([0,1,2,3,4,5])
for i in 0...1000 {
// Single actions
DispatchQueue.global(qos: .background).async {
usleep(useconds_t(Int.random(in: 100...10000)))
let num = i*i
arr.append(num)
print("arr.append(\(num)), background queue")
}
DispatchQueue.global(qos: .default).async {
usleep(useconds_t(Int.random(in: 100...10000)))
arr.append(arr.count)
print("arr.append(\(arr.count)), default queue")
}


// multy actions
DispatchQueue.global(qos: .utility).async {
arr.set { array -> [Int] in
var newArray = array
newArray.sort()
print("sort(), .utility queue")
return newArray
}
}
}

这是 Swift 4的答案,

let queue = DispatchQueue(label: "com.readerWriter", qos: .background, attributes: .concurrent)
var safeArray: [String] = []


subscript(index: Int) -> String {


get {
queue.sync {
return safeArray[index]
}
}


set(newValue) {
queue.async(flags: .barrier) { [weak self] in
self?.safeArray[index] = newValue
}
}
}

Swift-Nio & Vapor Swift

对于那些使用 Swift-Nio (或基于 Swift-Nio 的蒸汽 Swift)的用户,有一个内置的解决方案:

class MyClass {
let lock = Lock()
var myArray: Array<Int> = []


func networkRequestWhatEver() {
lock.withLock {
array.append(someValue)
}
}
}

请注意,在修改相同的 Array对象(或 Dictionary等)时,应该使用相同的 Lock对象。

Https://github.com/apple/swift-nio/blob/5e728b57862ce9e13877ff1edc9249adc933070a/sources/nioconcurrencyhelpers/lock.swift#l15

我不知道为什么人们对这么简单的事情采取这么复杂的方法

  • 不要滥用 DispatchQueues锁定。使用 queue.sync不过是获取一个锁并在锁(DispatchGroup)等待时将工作分派给另一个线程。这不仅是不必要的,而且还可能有副作用,这取决于您锁定的是什么。你可以在 资料来源里自己查。

    此外,GCD 与新的结构化并发 API 不能很好地混合在一起!

  • 不要使用 objc_sync_enter/exit,这些是由对象 @synchronized使用的,它将隐式地将 Swift 集合桥接到对应的对象,这也是不必要的。它是一个遗留的 API。

只需定义一个锁,并保护您的收集访问。

var lock = NSLock()
var a = [1, 2, 3]


lock.lock()
a.append(4)
lock.unlock()

如果你想让你的生活轻松一点,定义一个小的延伸。

extension NSLock {


@discardableResult
func with<T>(_ block: () throws -> T) rethrows -> T {
lock()
defer { unlock() }
return try block()
}
}


let lock = NSLock()
var a = [1, 2, 3]


lock.with { a.append(4) }

您还可以定义一个 @propertyWrapper,使成员 var成为原子的。

@propertyWrapper
struct Atomic<Value> {


private let lock = NSLock()
private var value: Value


init(default: Value) {
self.value = `default`
}


var wrappedValue: Value {
get {
lock.lock()
defer { lock.unlock() }
return value
}
set {
lock.lock()
value = newValue
lock.unlock()
}
}
}

最后但并非最不重要的原子类型还有 < strong > Swift Atomics

具有参与者的线程安全数据结构

在 Swift 5.5中,你可以用一个演员来表达:

actor SyncArray<T> {
private var buffer: [T]
    

init<S: Sequence>(_ elements: S) where S.Element == T {
buffer = Array(elements)
}
    

var count: Int {
buffer.count
}
    

func append(_ element: T) {
buffer.append(element)
}
    

@discardableResult
func remove(at index: Int) -> T {
buffer.remove(at: index)
}
}

它不仅使代码更简单,更不容易出错,而且更明确地指出了另一个答案中指出的潜在竞态条件:

Task {
let array = SyncArray([1])


if await array.count == 1 {
await array.remove(at: 0)
}
}

这里有两个暂停点,这意味着在调用 .remove(at:)时,数组 count可能已经更改。

这种先读后写的操作必须是原子的才能保持一致,因此它应该被定义为参与者的一个方法:

extension SyncArray {
func removeLastIfSizeOfOne() {
if buffer.count == 1 {
buffer.remove(at: 0)
}
}
}

上面,没有悬挂点表明操作是自动执行的。另一个不需要编写扩展就可以工作的解决方案是像下面这样使用 isolated关键字:

func removeLastIfSizeOfOne<T>(_ array: isolated SyncArray<T>) {
if array == 1 {
array(at: 0)
}
}

这将在整个调用期间而不是在其每个暂停点隔离传递的参与者。调用此函数只需要一个挂起点。

快速线程安全集合

在 Swift 中使某些东西(例如 Collection)线程安全的主要和最常见的想法是:

  1. 定制(本地) 并行队列
  2. 同步读取 . 通过 sync读取关键部分(共享资源)
  3. 异步书写具有强大的障碍

[ Swift Thread safe singleton ]

如果希望与数组进行线程安全的交互,则必须同步访问。建议了许多备选方案(其中一些被省略了) ,因此让我们调查一下各种同步备选方案:

  1. 串行分派队列: 这是一种直观的 GCD 模式。

  2. 具有并发队列的读写器模式: 这是对串行调度队列模式的一种优雅的改进,使用具有异步“写”的并发队列(这样调用者就不会等到写完)和一个屏障(以防止与“写”并发的任何交互) ,但它提供了并发“读”(允许在“读”期间进行更多并发)。这是一种复杂而吸引人的模式,但在实践中,只有当并发“读”和异步“写”的好处超过 GCD 开销时,它才有用。

  3. 锁具:

    • NSLock是一种快速而简单的锁定机制,在大多数情况下,它比任何 GCD 替代品的性能都要好:

      extension NSLocking {
      func synchronized<T>(_ block: () throws -> T) rethrows -> T {
      lock()
      defer { unlock() }
      return try block()
      }
      }
      
    • os_unfair_lock是另一种锁定机制,它甚至比 NSLock更快,但是在 Swift 中使用要稍微复杂一些。见 https://stackoverflow.com/a/66525671/1271826。但在性能至关重要的极少数情况下,不公平锁是一个令人信服的解决方案。

  4. Objective-C objc_sync_enterobjc_sync_exit API: 这在 Swift 的世界中没有实际意义。

  5. 信号量: 它在概念上类似于基于锁的方法,但是通常比任何基于锁的方法都慢,在这个对话中可以忽略它。

  6. Actors: Swift 5.5并发系统提供的同步机制。

简而言之,如果使用 async-await,参与者是合乎逻辑的选择。如果还没有采用 Swift 并发系统,我会倾向于采用基于锁的方法(这种方法简单快速) ,或者在极少数情况下采用 GCD 读写器方法。

在实践中,同步机制的选择在大多数用例中并不相关。(如果您正在进行如此多的同步,以至于性能差异变得非常重要,那么在详细讨论特定机制之前,您可能需要考虑如何减少同步点的数量。)也就是说,旧的同步机制(信号量、 objc_sync_enter等)将不再被考虑。


在概述了可能的同步机制之后,下一个问题是在什么级别执行同步。具体来说,已经不止一次地提出了用于整个数组的属性包装器。这里总是不适合进行同步。属性包装器方法提供了对数组的原子访问(这与线程安全性不完全相同) ,但是通常需要更高层次的抽象。例如,如果一个线程正在添加元素,而另一个线程正在读取或删除元素,您通常希望这些高级任务中的每一个都是同步的,而不仅仅是数组的单个访问。