我已经搜索了Swift的书籍,但找不到@synchronized的Swift版本。我如何做互斥在Swift?


当前回答

使用Bryan McLemore的答案,我扩展了它,以支持使用Swift 2.0延迟能力扔进安全庄园的对象。

func synchronized( lock:AnyObject, block:() throws -> Void ) rethrows
{
    objc_sync_enter(lock)
    defer {
        objc_sync_exit(lock)
    }

    try block()
}

其他回答

斯威夫特3

此代码具有重入能力,可以与异步函数调用一起工作。在这段代码中,someAsyncFunc()被调用之后,串行队列上的另一个函数闭包将被处理,但会被semapore .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不是一个好主意。

类似于Objective-C中的@synchronized指令,在Swift中可以有任意的返回类型和漂亮的重抛出行为。

// 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语句可以直接返回一个值,而不需要引入临时变量。


在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](我喜欢任意返回类型)和Tod Cunningham[2](我喜欢延迟)的答案。

图我将发布我的Swift 5实现,建立在前面的答案。谢谢你们了!我发现有一个返回值的方法也很有用,所以我有两个方法。

这是一个简单的类首先创建:

import Foundation
class Sync {
public class func synced(_ lock: Any, closure: () -> ()) {
        objc_sync_enter(lock)
        defer { objc_sync_exit(lock) }
        closure()
    }
    public class func syncedReturn(_ lock: Any, closure: () -> (Any?)) -> Any? {
        objc_sync_enter(lock)
        defer { objc_sync_exit(lock) }
        return closure()
    }
}

如果需要返回值,就像这样使用它:

return Sync.syncedReturn(self, closure: {
    // some code here
    return "hello world"
})

Or:

Sync.synced(self, closure: {
    // do some work synchronously
})

在2018年WWDC的“理解崩溃和崩溃日志”会议414中,他们展示了以下使用DispatchQueues与sync的方法。

在swift 4中应该像下面这样:

class ImageCache {
    private let queue = DispatchQueue(label: "sync queue")
    private var storage: [String: UIImage] = [:]
    public subscript(key: String) -> UIImage? {
        get {
          return queue.sync {
            return storage[key]
          }
        }
        set {
          queue.sync {
            storage[key] = newValue
          }
        }
    }
}

无论如何,您也可以使用带屏障的并发队列使读取更快。同步和异步读取同时执行,写入新值等待前一个操作完成。

class ImageCache {
    private let queue = DispatchQueue(label: "with barriers", attributes: .concurrent)
    private var storage: [String: UIImage] = [:]

    func get(_ key: String) -> UIImage? {
        return queue.sync { [weak self] in
            guard let self = self else { return nil }
            return self.storage[key]
        }
    }

    func set(_ image: UIImage, for key: String) {
        queue.async(flags: .barrier) { [weak self] in
            guard let self = self else { return }
            self.storage[key] = image
        }
    }
}

在现代Swift 5中,具有返回功能:

/**
Makes sure no other thread reenters the closure before the one running has not returned
*/
@discardableResult
public func synchronized<T>(_ lock: AnyObject, closure:() -> T) -> T {
    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }

    return closure()
}

像这样使用它,以利用返回值功能:

let returnedValue = synchronized(self) { 
     // Your code here
     return yourCode()
}

或者像这样:

synchronized(self) { 
     // Your code here
    yourCode()
}