单例中吸气剂和定位器的螺纹安全性

时间:2017-08-16 09:44:12

标签: ios swift swift3

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

由于我将init()私有,并且还声明了shared实例为static let,我认为初始化程序是线程安全的。但是myName的getter和setter函数呢,它们是否安全?

2 个答案:

答案 0 :(得分:15)

稍微不同的方法(这来自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
            }
        }
    }
}
  • 使用并发队列意味着来自多个线程的多次读取不会相互阻塞。由于获取时没有变异,因此可以同时读取该值,因为......
  • 我们使用.barrier异步调度设置新值。该块可以异步执行,因为调用者不需要等待设置该值。只有在其前面的并发队列中的所有其他块完成之后,才会运行该块。因此,当此setter等待运行时,现有的挂起读取不会受到影响。屏障意味着当它开始运行时,不会运行其他块。实际上,在设置器的持续时间内将队列转换为串行队列。在此块完成之前,不能再进一步读取。当块已完成时,已设置新值,此setter之后添加的任何getter现在可以同时运行。

答案 1 :(得分:13)

你说的那些在你写的那些获取者不是线程安全的。在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"
    }
}

使用串行调度队列将保证先进先出执行以及实现"锁定"关于数据。也就是说,在更改数据时无法读取数据。在这种方法中,我们使用sync来执行实际的数据读取和写入,这意味着调用者总是被迫等待轮到其他类似于其他锁定原语。

注意:这不是most performant方法,但是阅读和理解起来很简单。这是一个很好的通用解决方案,可以避免竞争条件,但并不意味着为并行算法开发提供同步。

来源: https://mikeash.com/pyblog/friday-qa-2015-02-06-locks-thread-safety-and-swift.html What is the Swift equivalent to Objective-C's "@synchronized"?