我正在使用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。
- >忘了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() {}
}
答案 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可能会对您的情况有所帮助。