GCD со статическими функциями структуры
Как бы вы применили поточно-ориентированную функциональность к статическим функциям структуры
class SingleSome {
struct Static {
private static var instance: SingleSome?
//need barrier sync
static func getInstance(block: () -> SingleSome) -> SingleSome {
if instance == nil {
instance = block()
}
return instance!
}
static func remove() { //need barrier sync
instance = nil
}
}
}
причина, по которой блок был использован в качестве параметра, поскольку могут быть унаследованные объекты SingleSome
2 ответа
Решение
Вы можете использовать частную последовательную очередь, чтобы гарантировать, что только один поток может быть в любой из критических секций в любой момент.
class SingleSome {
struct Static {
private static let queue = dispatch_queue_create("SingleSome.Static.queue", nil)
private static var instance: SingleSome?
static func getInstance(block: () -> SingleSome) -> SingleSome {
var myInstance: SingleSome?
dispatch_sync(queue) {
if self.instance == nil {
self.instance = block()
}
myInstance = self.instance
}
// This return has to be outside the dispatch_sync block,
// so there's a race condition if I return instance directly.
return myInstance!
}
static func remove() {
dispatch_sync(queue) {
self.instance = nil
}
}
}
}
Используйте семафор, dispatch_sync не подходит, потому что вам нужно синхронное возвращаемое значение из getInstance:
class SingleSome {
struct Static {
private static var instance: SingleSome?
private static let lock = dispatch_semaphore_create(1)
//need barrier sync
static func getInstance(block: () -> SingleSome) -> SingleSome {
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER)
var value = instance
if value == nil {
instance = block()
value = instance
}
dispatch_semaphore_signal(lock)
return value!
}
static func remove() { //need barrier sync
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER)
instance = nil
dispatch_semaphore_signal(lock)
}
}
}
Также обратите внимание, что как написано, это может привести к взаимоблокировкам, если блок приводит к удалению или вызову getInstance как dispatch_semaphore_t не является рекурсивным потоком