如何在 Swift 中原子地递增变量? [英] How do I atomically increment a variable in Swift?
问题描述
我希望能够以原子方式递增计数器,但找不到任何有关如何执行此操作的参考.
I want to be able to increment a counter atomically and I can't find any reference on how to do it.
根据评论添加更多信息:
Adding more information based on comments:
- 您在使用 GCD 吗?不,我没有使用 GCD.必须使用队列系统来递增数字似乎有点过头了.
- 是否您了解基本的线程安全吗?是的,否则我不会询问原子增量.
- 这个变量是本地变量吗?号
- 是实例级别吗?是的,它应该是单个实例的一部分.
- Are you using GCD? No. I am not using GCD. Having to use a queue system to increment a number seems overkill.
- Do You understand basic thread safety? Yes I do otherwise I would not be asking about atomic increments.
- Is this variable local? No.
- Is it instance level? Yes it should be part of a single instance.
我想做这样的事情:
class Counter {
private var mux Mutex
private (set) value Int
func increment (){
mux.lock()
value += 1
mux.unlock()
}
}
推荐答案
来自 低级并发 API:
有一长串 OSAtomicIncrement 和 OSAtomicDecrement允许您递增和递减整数值的函数以原子方式 – 线程安全,无需锁定(或使用队列).如果您需要增加全局计数器,这些会很有用从多个线程进行统计.如果你所做的只是增加一个全局计数器,无障碍OSAtomicIncrement版本就可以了,当没有争用时,他们打电话很便宜.
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.
这些函数适用于固定大小的整数,您可以选择根据您的需要选择 32 位或 64 位变体:
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)
}
}
(注意:正如 Erik Aigner 正确注意到的那样,OSAtomicIncrement32
和从 macOS 10.12/iOS 10.10 开始不推荐使用朋友.Xcode 8 建议改用
中的函数.然而这似乎很难,比较 Swift 3:atomic_compare_exchange_strong 和 https://openradar.appspot.com/27161329.因此,以下基于 GCD 的方法似乎是最好的立即解决.)
(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.)
或者,可以使用 GCD 队列进行同步.来自 调度队列:
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.
在你的情况下
// 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
}
}
}
参见 向 Swift 添加项目跨多个线程的数组导致问题(因为数组不是线程安全的) - 我该如何解决? 或 GCD 与结构的静态函数 用于更复杂的示例.这个线程dispatch_sync 比@synchronized 有什么优势?也很有趣.
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.
这篇关于如何在 Swift 中原子地递增变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!