swift中的线程安全单例 [英] Thread safe singleton in swift

查看:48
本文介绍了swift中的线程安全单例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个应用程序,它有一个单例,用于存储整个应用程序的信息.但是,当使用来自不同线程的单例时,这会产生一些数据竞争问题.

I have and Application which has a singleton that stores information across the whole app. However, this is creating some data race issues when using the singleton from different threads.

这里有一个非常虚拟和简单的问题版本:

Here there is a very dummy and simplistic version of the problem:

单身

class Singleton {
    static var shared = Singleton()

    var foo: String = "foo"
}

单例的使用(为了简单起见,来自 AppDelegate)

Use of the singleton (from the AppDelegate for simplicity)

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
    }
}

有什么方法可以确保单例是线程安全的,这样它就可以在应用程序的任何地方使用,而不必担心您在哪个线程中?

Is there any way to ensure that a singleton is thread safe, so it can be used from anywhere in the app without having to worry about which thread you are in?

这个问题不是重复在 Swift 中使用 dispatch_once 单例模型 因为(如果我理解正确的话)在那里他们解决了访问单例对象本身的问题,但不能确保其属性的读取和写入是线程安全的.

This question is not a duplicate of Using a dispatch_once singleton model in Swift since (if I understood it correctly) in there they are addressing the problem of accessing to the singleton object itself, but not ensuring that the reading and writing of its properties is done thread safely.

推荐答案

感谢@rmaddy 的评论为我指明了正确的方向,我能够解决问题.

Thanks to @rmaddy comments which pointed me in the right direction I was able to solve the problem.

为了使Singleton线程的foo属性安全,需要修改如下:

In order to make the property foo of the Singleton thread safe, it need to be modified as follows:

    class Singleton {

    static let shared = Singleton()

    private init(){}

    private let internalQueue = DispatchQueue(label: "com.singletioninternal.queue",
                                              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
    }
}

线程安全是通过计算属性 foo 实现的,该属性使用 internalQueue 来访问真实的"_foo 属性.

Thread safety is accomplished by having a computed property foo which uses an internalQueue to access the "real" _foo property.

此外,为了获得更好的性能,internalQueue 被创建为并发.这意味着在写入属性时需要添加 barrier 标志.

Also, in order to have better performance internalQueue is created as concurrent. And it means that it is needed to add the barrier flag when writing to the property.

barrier 标志的作用是确保在队列中所有先前安排的工作项都完成后执行工作项.

What the barrier flag does is to ensure that the work item will be executed when all previously scheduled work items on the queue have finished.

这篇关于swift中的线程安全单例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆