我在Swift 3中创建了一个简单的单例:
class MySingleton {
private var myName: String
private init() {}
static let shared = MySingleton()
func setName(_ name: String) {
myName = name
}
func getName() -> String {
return myName
}
}
Run Code Online (Sandbox Code Playgroud)
由于我创建了init()私有的,也声明了shared实例static let,我认为初始化程序是线程安全的.但是getter和setter函数myName呢,它们是否安全?
Abi*_*ern 20
稍微不同的方法(这是来自Xcode 9 Playground)是使用并发队列而不是串行队列.
final class MySingleton {
static let shared = MySingleton()
private let nameQueue = DispatchQueue(label: "name.accessor", qos: .default, attributes: .concurrent)
private var _name = "Initial name"
private init() {}
var name: String {
get {
var name = ""
nameQueue.sync {
name = _name
}
return name
}
set {
nameQueue.async(flags: .barrier) {
self._name = newValue
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
.barrier异步调度设置新值.该块可以异步执行,因为调用者不需要等待设置该值.只有在其前面的并发队列中的所有其他块完成之后,才会运行该块.因此,当此setter等待运行时,现有的挂起读取不会受到影响.屏障意味着当它开始运行时,不会运行其他块.实际上,在设置器的持续时间内将队列转换为串行队列.在此块完成之前,不能再进一步读取.当块已完成时,已设置新值,此setter之后添加的任何getter现在可以同时运行.all*_*enh 16
你写的那些获取者不是线程安全的,你是对的.在Swift中,目前实现此目的的最简单(读取最安全)方法是使用Grand Central Dispatch队列作为锁定机制.最简单(也是最容易理解)的方法是使用基本的串行队列.
class MySingleton {
static let shared = MySingleton()
// Serial dispatch queue
private let lockQueue = DispatchQueue(label: "MySingleton.lockQueue")
private var _name: String
var name: String {
get {
return lockQueue.sync {
return _name
}
}
set {
lockQueue.sync {
_name = newValue
}
}
}
private init() {
_name = "initial name"
}
}
Run Code Online (Sandbox Code Playgroud)
使用串行调度队列将保证先进先出执行以及实现对数据的"锁定".也就是说,在更改数据时无法读取数据.在这种方法中,我们使用sync来执行实际的数据读取和写入,这意味着调用者总是被迫等待轮到其他类似于其他锁定原语.
注意:这不是最高效的方法,但它易于阅读和理解.它是避免竞争条件的良好通用解决方案,但并不意味着为并行算法开发提供同步.
来源:https : //mikeash.com/pyblog/friday-qa-2015-02-06-locks-thread-safety-and-swift.html 什么是Swift等同于Objective-C的"@synchronized"?
| 归档时间: |
|
| 查看次数: |
3309 次 |
| 最近记录: |