Swift 中的互斥替代品

问题描述 投票:0回答:5

我在多个线程之间有一个共享内存。我想阻止这些线程同时访问这块内存。 (比如生产者-消费者问题)

问题

一个线程向队列添加元素,另一个线程读取这些元素并删除它们。他们不应该同时访问队列。

此问题的一个解决方案是使用互斥体。

我发现,Swift 中没有 Mutex。 Swift 有其他选择吗?

ios swift swift3 concurrency mutual-exclusion
5个回答
22
投票

对此有很多解决方案,但我使用串行队列来执行此类操作:

let serialQueue = DispatchQueue(label: "queuename")
serialQueue.sync { 
    //call some code here, I pass here a closure from a method
}

编辑/更新:也适用于信号量:

let higherPriority = DispatchQueue.global(qos: .userInitiated)
let lowerPriority = DispatchQueue.global(qos: .utility)

let semaphore = DispatchSemaphore(value: 1)

func letUsPrint(queue: DispatchQueue, symbol: String) {
    queue.async {
        debugPrint("\(symbol) -- waiting")
        semaphore.wait()  // requesting the resource

        for i in 0...10 {
            print(symbol, i)
        }

        debugPrint("\(symbol) -- signal")
        semaphore.signal() // releasing the resource
    }
}

letUsPrint(queue: lowerPriority, symbol: "Low Priority Queue Work")
letUsPrint(queue: higherPriority, symbol: "High Priority Queue Work")

RunLoop.main.run()

17
投票

感谢beshio的评论,您可以像这样使用信号量:

let semaphore = DispatchSemaphore(value: 1)

在使用资源之前使用等待:

semaphore.wait()
// use the resource

使用后释放它:

semaphore.signal()

在每个线程中执行此操作。


12
投票

正如人们(包括我)评论的那样,有几种方法可以实现这种锁定。但我认为调度信号量比其他信号量更好,因为它的开销似乎最小。正如 Apples doc“Replacing Semaphore Code” 中所发现的,除非信号量已经锁定(= 零),否则它不会进入内核空间,这是代码进入内核以切换信号量的唯一情况。线。我认为信号量在大多数情况下不为零(但这当然是应用程序特定的问题)。因此,我们可以避免大量开销。

还有一个关于调度信号量的评论,这与上面的情况相反。如果您的线程具有不同的执行优先级,并且较高优先级的线程必须长时间锁定信号量,则调度信号量可能不是解决方案。这是因为等待线程之间没有“队列”。在这种情况下发生的是更高的优先级 线程大多数时候都会获取并锁定信号量,而较低优先级的线程只能偶尔锁定信号量,因此,大多数情况下只是等待。如果这种行为对您的应用程序不利,您必须考虑使用调度队列。


2
投票

您可以使用 NSLock 或 NSRecursiveLock。如果您需要从另一个锁定函数调用一个锁定函数,请使用递归版本。

class X {
  let lock = NSLock()

  func doSome() {
    lock.lock()
    defer { lock.unlock() }
    //do something here
  }

}

0
投票

在现代平台(macOS 10.12+、iOS 10+)上

os_unfair_lock
是一种高性能、高效的通用互斥体,特别是当您的关键部分很短时。它比队列轻量得多(小 30 倍)并跟踪优先级,防止
DispatchSemaphore
可能发生的反转。

与大多数低级同步原语一样,它需要有一个稳定的地址,因此您应该自己分配它,或者您可以使用

OSAllocatedUnfairLock
(如果在较新的(macOS 13+、iOS 16+)系统上可用)。如果这些不适合您,或者您不太习惯直接使用锁,
NSLock
会增加少量开销,但不是一个糟糕的选择。特别是与队列或信号量相比:)

© www.soinside.com 2019 - 2024. All rights reserved.