From Low-Level Concurrency APIs:
There’s a long list of OSAtomicIncrement and OSAtomicDecrement
functions that allow you to increment and decrement an integer value
in an atomic way – thread safe without having to take a lock (or use
queues). These can be useful if you need to increment global counters
from multiple threads for statistics. If all you do is increment a
global counter, the barrier-free OSAtomicIncrement versions are fine,
and when there’s no contention, they’re cheap to call.
These functions work with fixed-size integers, you can choose
the 32-bit or 64-bit variant depending on your needs:
class Counter {
private (set) var value : Int32 = 0
func increment () {
OSAtomicIncrement32(&value)
}
}
(Note: As Erik Aigner correctly noticed, OSAtomicIncrement32
and
friends are deprecated as of macOS 10.12/iOS 10.10. Xcode 8 suggests to use functions from <stdatomic.h>
instead. However that seems to be difficult,
compare Swift 3: atomic_compare_exchange_strong and https://openradar.appspot.com/27161329.
Therefore the following GCD-based approach seems to be the best
solution now.)
Alternatively, one can use a GCD queue for synchronization.
From Dispatch Queues in the "Concurrency Programming Guide":
... With dispatch queues, you could add both tasks to a serial
dispatch queue to ensure that only one task modified the resource at
any given time. This type of queue-based synchronization is more
efficient than locks because locks always require an expensive kernel
trap in both the contested and uncontested cases, whereas a dispatch
queue works primarily in your application’s process space and only
calls down to the kernel when absolutely necessary.
In your case that would be
// Swift 2:
class Counter {
private var queue = dispatch_queue_create("your.queue.identifier", DISPATCH_QUEUE_SERIAL)
private (set) var value: Int = 0
func increment() {
dispatch_sync(queue) {
value += 1
}
}
}
// Swift 3:
class Counter {
private var queue = DispatchQueue(label: "your.queue.identifier")
private (set) var value: Int = 0
func increment() {
queue.sync {
value += 1
}
}
}
See Adding items to Swift array across multiple threads causing issues (because arrays aren't thread safe) - how do I get around that? or GCD with static functions of a struct for more sophisticated examples. This thread
What advantage(s) does dispatch_sync have over @synchronized? is also very interesting.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…