什么是Swift相当于Objective-C的“@synchronized”?
我search了Swift书,但是找不到@synchronized的Swift版本。 我如何在Swift中互相排斥?
我正在使用GCD。 它比@synchronized
稍微冗长些,但作为一个replace完美地工作:
let lockQueue = dispatch_queue_create("com.test.LockQueue", nil) dispatch_sync(lockQueue) { // code }
我一直在寻找这个,并得出这样的结论,这里面没有任何本地构造。
基于我从Matt Bridges和其他人看到的一些代码,我做了这个小帮手函数。
func synced(_ lock: Any, closure: () -> ()) { objc_sync_enter(lock) closure() objc_sync_exit(lock) }
用法非常简单
synced(self) { println("This is a synchronized closure") }
我发现有一个问题。 传入一个数组作为locking参数似乎会导致一个非常钝的编译器错误在这一点上。 否则,虽然它似乎按需要工作。
Bitcast requires both operands to be pointer or neither %26 = bitcast i64 %25 to %objc_object*, !dbg !378 LLVM ERROR: Broken function found, compilation aborted!
我喜欢和使用这里的许多答案,所以我会select最适合你的。 也就是说,当我需要像objective-c的@synchronized
这样的东西时,我更喜欢的方法使用了swift 2中引入的defer
语句。
{ objc_sync_enter(lock) defer { objc_sync_exit(lock) } // // code of critical section goes here // } // <-- lock released when this block is exited
关于这个方法的好处在于,你的关键部分可以以任何需要的方式(例如, return
, break
, continue
, throw
)退出包含块,并且“无论程序如何控制, “。 1
您可以在objc_sync_enter(obj: AnyObject?)
和objc_sync_exit(obj: AnyObject?)
之间夹入语句。 @synchronized关键字正在使用这些方法。 即
objc_sync_enter(self) ... synchronized code ... objc_sync_exit(self)
来自Objective-C的@synchronized
指令的模拟可以有一个任意的返回types,并且在Swift中有很好的rethrows
行为。
// Swift 3 func synchronized<T>(_ lock: AnyObject, _ body: () throws -> T) rethrows -> T { objc_sync_enter(lock) defer { objc_sync_exit(lock) } return try body() }
使用defer
语句可以直接返回一个值,而不需要引入一个临时variables。
在Swift 2中,将@noescape
属性添加到闭包中以允许更多的优化:
// Swift 2 func synchronized<T>(lock: AnyObject, @noescape _ body: () throws -> T) rethrows -> T { objc_sync_enter(lock) defer { objc_sync_exit(lock) } return try body() }
基于GNewc [1] (我喜欢任意返回types)和Tod Cunningham [2] (我喜欢defer
)的答案。
要添加返回function,你可以这样做:
func synchronize<T>(lockObj: AnyObject!, closure: ()->T) -> T { objc_sync_enter(lockObj) var retVal: T = closure() objc_sync_exit(lockObj) return retVal }
随后,您可以使用以下方式调用它:
func importantMethod(...) -> Bool { return synchronize(self) { if(feelLikeReturningTrue) { return true } // do other things if(feelLikeReturningTrueNow) { return true } // more things return whatIFeelLike ? true : false } }
使用Bryan McLemore的答案,我将它扩展为支持具有Swift 2.0延迟能力的安全庄园的对象。
func synchronized( lock:AnyObject, block:() throws -> Void ) rethrows { objc_sync_enter(lock) defer { objc_sync_exit(lock) } try block() }
SWIFT 3
在Swift 3中,您可以使用GCD调度队列来locking资源。
class MyObject { private var internalState: Int = 0 private let internalQueue: DispatchQueue = DispatchQueue(label:"LockingQueue") // Serial by default var state: Int { get { return internalQueue.sync { internalState } } set (newState) { internalQueue.sync { internalState = newState } } } }
Swift 3
这段代码具有重新进入的能力,可以使用asynchronous函数调用。 在这个代码中,在调用someAsyncFunc()之后,串行队列上的另一个函数闭包将被处理,但是被semaphore.wait()阻塞,直到调用signal()。 internalQueue.sync不应该被使用,因为如果我没有弄错它会阻塞主线程。
let internalQueue = DispatchQueue(label: "serialQueue") let semaphore = DispatchSemaphore(value: 1) internalQueue.async { self.semaphore.wait() // Critical section someAsyncFunc() { // Do some work here self.semaphore.signal() } }
objc_sync_enter / objc_sync_exit不是没有error handling的好主意。
在Swift4中使用NSLock :
let lock = NSLock() lock.lock() if isRunning == true { print("Service IS running ==> please wait") return } else { print("Service not running") } isRunning = true lock.unlock()
警告NSLock类使用POSIX线程来实现其locking行为。 向NSLock对象发送解锁消息时,必须确保消息是从发送初始locking消息的同一个线程发送的。 解锁来自不同线程的锁可能导致未定义的行为。
为什么使用锁来困难和麻烦? 使用调度障碍。
调度屏障在并发队列中创build同步点。
当它正在运行时,即使并发和其他核心可用,也不允许队列中的其他块运行。
如果这听起来像是独占(写)锁,那就是。 非屏障块可以被认为是共享(读)锁。
只要通过队列执行对资源的所有访问,障碍就提供了非常便宜的同步。
根据</s>euroburɳ ,testing一个子类的情况
class Foo: NSObject { func test() { print("1") objc_sync_enter(self) defer { objc_sync_exit(self) print("3") } print("2") } } class Foo2: Foo { override func test() { super.test() print("11") objc_sync_enter(self) defer { print("33") objc_sync_exit(self) } print("22") } } let test = Foo2() test.test()
输出:
1 2 3 11 22 33
dispatch_barrier_async是更好的方法,而不阻塞当前的线程。
dispatch_barrier_async(accessQueue,{dictionary [object.ID] = object})
总之,这里给出更常见的方式,包括返回值或者void,抛出
import基金会
extension NSObject { func synchronized<T>(lockObj: AnyObject!, closure: () throws -> T) rethrows -> T { objc_sync_enter(lockObj) defer { objc_sync_exit(lockObj) } return try closure() } }
细节
xCode 8.3.1,swift 3.1
任务
从不同线程读取写入值(asynchronous)。
码
class AsyncObject<T>:CustomStringConvertible { private var _value: T public private(set) var dispatchQueueName: String let dispatchQueue: DispatchQueue init (value: T, dispatchQueueName: String) { _value = value self.dispatchQueueName = dispatchQueueName dispatchQueue = DispatchQueue(label: dispatchQueueName) } func setValue(with closure: @escaping (_ currentValue: T)->(T) ) { dispatchQueue.sync { [weak self] in if let _self = self { _self._value = closure(_self._value) } } } func getValue(with closure: @escaping (_ currentValue: T)->() ) { dispatchQueue.sync { [weak self] in if let _self = self { closure(_self._value) } } } var value: T { get { return dispatchQueue.sync { _value } } set (newValue) { dispatchQueue.sync { _value = newValue } } } var description: String { return "\(_value)" } }
用法
print("Single read/write action") // Use it when when you need to make single action let obj = AsyncObject<Int>(value: 0, dispatchQueueName: "Dispatch0") obj.value = 100 let x = obj.value print(x) print("Write action in block") // Use it when when you need to make many action obj.setValue{ (current) -> (Int) in let newValue = current*2 print("previous: \(current), new: \(newValue)") return newValue }
完整的示例
扩展DispatchGroup
extension DispatchGroup { class func loop(repeatNumber: Int, action: @escaping (_ index: Int)->(), completion: @escaping ()->()) { let group = DispatchGroup() for index in 0...repeatNumber { group.enter() DispatchQueue.global(qos: .utility).async { action(index) group.leave() } } group.notify(queue: DispatchQueue.global(qos: .userInitiated)) { completion() } } }
类ViewController
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //sample1() sample2() } func sample1() { print("=================================================\nsample with variable") let obj = AsyncObject<Int>(value: 0, dispatchQueueName: "Dispatch1") DispatchGroup.loop(repeatNumber: 5, action: { index in obj.value = index }) { print("\(obj.value)") } } func sample2() { print("\n=================================================\nsample with array") let arr = AsyncObject<[Int]>(value: [], dispatchQueueName: "Dispatch2") DispatchGroup.loop(repeatNumber: 15, action: { index in arr.setValue{ (current) -> ([Int]) in var array = current array.append(index*index) print("index: \(index), value \(array[array.count-1])") return array } }) { print("\(arr.value)") } } }
另一种方法是创build一个超类,然后inheritance它。 这样您可以更直接地使用GCD
class Lockable { let lockableQ:dispatch_queue_t init() { lockableQ = dispatch_queue_create("com.blah.blah.\(self.dynamicType)", DISPATCH_QUEUE_SERIAL) } func lock(closure: () -> ()) { dispatch_sync(lockableQ, closure) } } class Foo: Lockable { func boo() { lock { ....... do something } }