Hasable协议的自动原子唯一ID

时间:2015-11-03 09:06:44

标签: swift

我正在使用Singleton来生成符合Hashable的唯一ID。然后我意识到这不是真正的线程安全。所以我切换到OSAtomicIncrement32因为它没有使用闭包,所以它可以这么简单:

class HashID {

    static let sharedID = HashID()

    private var storedGlobalID : Int32 = 0
    var newID : Int {
        get {
            return Int(OSAtomicIncrement32(&storedGlobalID))
        }
    }

    private init() {}
}

然后我想为每个Type尝试一个HashID。所以我使用 _stdlib_getDemangledTypeName reflecting来提供字典。但话又说它不是线程安全的。不同的线程现在可以同时操作Dictionary。

class HashID {

    static let sharedID = HashTypeID()

    func idForType(type: Any.Type) -> Int {

        let typeName = _stdlib_getDemangledTypeName(type)

        guard let currentID = storedGlobalIDForType[typeName] else {

            let currentID : Int32 = 0
            storedGlobalIDForType[typeName] = currentID
            return Int(currentID)

        }

        let newID = atomicIncrement(currentID)
        storedGlobalIDForType[typeName] = newID
        return Int(newID)

    }

    private var storedGlobalIDForType : [String:Int32] = [String:Int32]()

    private func atomicIncrement(var value: Int32) -> Int32 {
        return OSAtomicIncrement32(&value)
    }

    private init() {}

}

我显然可以使用GCD,但这意味着使用闭包然后我不能使用带返回值的简单函数。使用completionHandler不那么“干净”,并且它使得在类/结构的init中设置它变得更加复杂。

<击>

这意味着默认ID,这会使它们在获取ID之前不可用,或者我必须拥有一个带有自己的completionHandler的init。 - &GT;忘了dispatch_sync是如何工作的。

正如我所说,我只是在玩这个代码。第一个功能非常好。然而,第二个也给出了所创建类型的所有实例的计数。哪个不是最有用的东西......

我有什么方法可以忘记访问Dictionary的线程吗?

更新代码:

致Martin R和Nikolai Ruhe

class HashTypeID {
    // shared instance
    static let sharedID = HashTypeID()

    // dict for each type
    private var storedGlobalIDForType : [String:Int] = [String:Int]()

    // serial queue
    private let _serialQueue = dispatch_queue_create("HashQueue", DISPATCH_QUEUE_SERIAL)


    func idForType(type: Any.Type) -> Int {

        var id : Int = 0

        // make it thread safe
        dispatch_sync(_serialQueue) {

            let typeName = String(reflecting: type)

            // check if there is already an ID
            guard let currentID = self.storedGlobalIDForType[typeName] else {

                // if there isn't an ID, store one
                let currentID : Int = 0
                self.storedGlobalIDForType[typeName] = currentID
                id = Int(currentID)

                return
            }

            // if there is an ID, increment
            id = currentID
            id++

            // store the incremented ID
            self.storedGlobalIDForType[typeName] = id
        }

        return id
    }

    private init() {}

}

1 个答案:

答案 0 :(得分:1)

  

有什么方法我忘记了访问Dictionary线程的安全吗?

很多。在串行队列上使用dispatch_sync是一种简单易行的方法:

class HashID {

    static func idForType(type: Any.Type) -> Int {

        let typeName = _stdlib_getDemangledTypeName(type)
        var id : Int = 0

        dispatch_sync(queue) {

            if let currentID = storedGlobalIDForType[typeName] {
                id = currentID + 1
                storedGlobalIDForType[typeName] = id
            } else {
                storedGlobalIDForType[typeName] = 0
            }
        }

        return id
    }

    private static var queue = dispatch_queue_create("my.queue", DISPATCH_QUEUE_SERIAL)
    private static var storedGlobalIDForType : [String : Int] = [:]
}

使用read write lock可能会对您的情况有所帮助。