什么是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 

关于这个方法的好处在于,你的关键部分可以以任何需要的方式(例如, returnbreakcontinuethrow )退出包含块,并且“无论程序如何控制, “。 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 } }