nik*_*ano 13 thread-safety swift swift4
我有和应用程序有一个单一的存储整个应用程序的信息.但是,当使用来自不同线程的单例时,这会产生一些数据争用问题.
这里有一个非常虚拟和简单化的问题版本:
独生子
class Singleton {
static var shared = Singleton()
var foo: String = "foo"
}
Run Code Online (Sandbox Code Playgroud)
单例的使用(为简单起见,来自AppDelegate)
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
DispatchQueue.global().async {
var foo = Singleton.shared.foo // Causes data race
}
DispatchQueue.global().async {
Singleton.shared.foo = "bar" // Causes data race
}
return true
}
}
Run Code Online (Sandbox Code Playgroud)
有没有办法确保单例是线程安全的,所以它可以在应用程序的任何地方使用,而不必担心你在哪个线程?
这个问题不是在Swift中使用dispatch_once单例模型的重复,因为(如果我理解正确的话)那里他们正在解决访问单例对象本身的问题,但不能确保其属性的读写完成线程安全.
nik*_*ano 25
感谢@rmaddy的评论指出了我正确的方向,我能够解决问题.
为了使财产foo的的Singleton线程安全的,它需要修改如下:
class Singleton {
static var shared = Singleton()
private let internalQueue = DispatchQueue(label: "SingletionInternalQueue", qos: .default, attributes: .concurrent)
private var _foo: String = "aaa"
var foo: String {
get {
return internalQueue.sync { _foo }
}
set (newState) {
internalQueue.async(flags: .barrier) { self._foo = newState }
}
}
func setup(string: String) {
foo = string
}
}
Run Code Online (Sandbox Code Playgroud)
线程安全是通过使用计算属性来完成的,该属性foo使用internalQueue来访问"real" _foo属性.
此外,为了获得更好的性能internalQueue,创建为并发.这意味着barrier在写入属性时需要添加标志.
什么barrier标志的作用是确保当队列上的所有先前安排的工作项目已完成工作项目将被执行.
| 归档时间: |
|
| 查看次数: |
3994 次 |
| 最近记录: |