Concurrency Swift与Objective-C';s"@同步的;?

Concurrency Swift与Objective-C';s"@同步的;?,concurrency,mutex,swift,Concurrency,Mutex,Swift,我搜索了Swift书籍,但找不到@synchronized的Swift版本。如何在Swift中实现互斥?您可以在objc\u sync\u enter(obj:AnyObject?和objc\u sync\u exit(obj:AnyObject?)之间夹杂语句。@synchronized关键字在幕后使用这些方法。i、 e objc_sync_enter(self) ... synchronized code ... objc_sync_exit(self) 你可以使用GCD。它比@synch

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

您可以在
objc\u sync\u enter(obj:AnyObject?
objc\u sync\u exit(obj:AnyObject?)之间夹杂语句。@synchronized关键字在幕后使用这些方法。i、 e

objc_sync_enter(self)
... synchronized code ...
objc_sync_exit(self)

你可以使用GCD。它比
@synchronized
稍微详细一些,但可以作为替代:

let serialQueue = DispatchQueue(label: "com.test.mySerialQueue")
serialQueue.sync {
    // code
}

我自己也在寻找这一点,并得出结论,swift内部还没有针对这一点的本地构造

我的确是根据我从Matt Bridges和其他人那里看到的一些代码编写了这个小助手函数

func synced(_ lock: Any, closure: () -> ()) {
    objc_sync_enter(lock)
    closure()
    objc_sync_exit(lock)
}
用法非常简单

synced(self) {
    println("This is a synchronized closure")
}
我发现了一个问题。此时,作为lock参数传入数组似乎会导致非常迟钝的编译器错误。否则,尽管它似乎按预期工作

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!

要添加返回函数,可以执行以下操作:

func synchronize<T>(lockObj: AnyObject!, closure: ()->T) -> T
{
  objc_sync_enter(lockObj)
  var retVal: T = closure()
  objc_sync_exit(lockObj)
  return retVal
}

另一种方法是创建一个超类,然后继承它。这样,您可以更直接地使用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
        }
    }

为什么要让锁变得困难和麻烦? 使用调度屏障

调度屏障在并发队列中创建同步点。 当它运行时,队列上的任何其他块都不允许运行,即使它是并发的并且其他核心可用。 如果这听起来像是一个独占(写)锁,那么它就是。 可以将非屏障块视为共享(读取)锁。
只要所有对资源的访问都是通过队列执行的,屏障就可以提供非常便宜的同步。

我喜欢并使用这里的许多答案,所以我会选择最适合您的答案。也就是说,当我需要像objective-c的
@synchronized
这样的东西时,我更喜欢的方法使用swift 2中介绍的语句

{ 
    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }

    //
    // code of critical section goes here
    //

} // <-- lock released when this block is exited
{
objc_同步_输入(锁定)
延迟{objc_sync_exit(lock)}
//
//关键部分的代码在这里
//

}//使用Bryan McLemore的回答,我扩展了它,以支持在具有Swift 2.0延迟功能的安全庄园中放置的对象

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

    try block()
}
Objective-C指令的模拟在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()
}
根据GNewc(我喜欢任意返回类型)和Tod Cunningham(我喜欢延迟
)的答案,测试一个子类案例

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()
输出:
dispatch\u barrier\u async是更好的方法,同时不阻塞当前线程

dispatch\u barrier\u async(访问队列{ 字典[object.ID]=对象
})

总之,这里给出了更常见的方法,包括返回值或void,以及抛出

import Foundation

extension NSObject {


    func synchronized<T>(lockObj: AnyObject!, closure: () throws -> T) rethrows ->  T
    {
        objc_sync_enter(lockObj)
        defer {
            objc_sync_exit(lockObj)
        }

        return try closure()
    }


}
<代码>导入基础 扩展NSObject{ func synchronized(lockObj:AnyObject!),闭包:()抛出->T)重试->T { 对象同步输入(锁定对象) 推迟{ objc_同步_退出(锁定OBJ) } 返回try闭包() } }
SWIFT 4

在Swift 4中,您可以使用GCDs调度队列锁定资源

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

此代码具有重入功能,可以处理异步函数调用。在这段代码中,调用someAsyncFunc()后,将处理串行队列上的另一个函数闭包,但会被信号量阻塞。请等待()直到调用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不是一个好主意。

详细信息 代码8.3.1,Swift 3.1

任务 从不同线程读写值(异步)

代码 类视图控制器

导入UIKit
类ViewController:UIViewController{
重写func viewDidLoad(){
super.viewDidLoad()
//样本1()
样本2()
}
func样本1(){
打印(“带变量的样本”)
设obj=AsyncObject(值:0,dispatchQueueName:“Dispatch1”)
DispatchGroup.loop(repeatNumber:5,action:{index in
obj.value=索引
}) {
打印(“\(对象值)”)
}
}
func样本2(){
打印(“\n=========================================================================\n带阵列的采样”)
设arr=AsyncObject(值:[],dispatchQueueName:“Dispatch2”)
DispatchGroup.loop(repeatNumber:15,action:{index in
arr.setValue{(当前)->([Int])在
var数组=当前
array.append(索引*索引)
打印(“索引:\(索引),值\(数组[array.count-1]))
返回数组
}
}) {
打印(“\(arr.value)”)
}
}
}
在Swift4中使用:

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线程来实现其锁定行为。向NSLock对象发送解锁消息时,必须确保该消息是从发送初始锁定消息的同一线程发送的。从不同线程解锁锁可能会导致未定义的行为

在2018年WWDC的“了解崩溃和崩溃日志”中,他们展示了使用带有同步的DispatchQueues的以下方法

在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实现,基于之前的答案。谢谢大家!我发现有一个返回值的方法也很有用,所以我有两个方法

下面是一个简单的类:

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"
})
或:

尝试:

同一线程可以多次获取的锁,无需 造成僵局的

Objective-C同步功能支持
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()
        }
    }
}
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)")
        }
    }
}
let lock = NSLock()
lock.lock()
if isRunning == true {
        print("Service IS running ==> please wait")
        return
} else {
    print("Service not running")
}
isRunning = true
lock.unlock()
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
        }
    }
}
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"
})
Sync.synced(self, closure: {
    // do some work synchronously
})
let lock = NSRecursiveLock()

func f() {
    lock.lock()
    //Your Code
    lock.unlock()
}

func f2() {
    lock.lock()
    defer {
        lock.unlock()
    }
    //Your Code
}
/**
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()
}
@NCCSerialized var foo: Int = 10
@NCCSerialized var myData: [SomeStruct] = []