我已经搜索了Swift的书籍,但找不到@synchronized的Swift版本。我如何做互斥在Swift?
当前回答
试题:NSRecursiveLock
一种锁,可以被同一线程多次获得 导致死锁。
let lock = NSRecursiveLock()
func f() {
lock.lock()
//Your Code
lock.unlock()
}
func f2() {
lock.lock()
defer {
lock.unlock()
}
//Your Code
}
Objective-C同步特性支持递归和 可重入代码。线程可以多次使用同一个信号量 递归的方式;其他线程被阻止使用它,直到 线程释放使用它获得的所有锁;也就是说,每一个 @synchronized()块正常退出或通过异常退出。 源
其他回答
随着Swift并发的出现,我们将使用actor。
You can use tasks to break up your program into isolated, concurrent pieces. Tasks are isolated from each other, which is what makes it safe for them to run at the same time, but sometimes you need to share some information between tasks. Actors let you safely share information between concurrent code. Like classes, actors are reference types, so the comparison of value types and reference types in Classes Are Reference Types applies to actors as well as classes. Unlike classes, actors allow only one task to access their mutable state at a time, which makes it safe for code in multiple tasks to interact with the same instance of an actor. For example, here’s an actor that records temperatures: actor TemperatureLogger { let label: String var measurements: [Int] private(set) var max: Int init(label: String, measurement: Int) { self.label = label self.measurements = [measurement] self.max = measurement } } You introduce an actor with the actor keyword, followed by its definition in a pair of braces. The TemperatureLogger actor has properties that other code outside the actor can access, and restricts the max property so only code inside the actor can update the maximum value.
要了解更多信息,请参见WWDC视频《使用Swift actor保护可变状态》。
为了完整起见,历史上的替代方案包括:
GCD serial queue: This is a simple pre-concurrency approach to ensure that one one thread at a time will interact with the shared resource. Reader-writer pattern with concurrent GCD queue: In reader-writer patterns, one uses a concurrent dispatch queue to perform synchronous, but concurrent, reads (but concurrent with other reads only, not writes) but perform writes asynchronously with a barrier (forcing writes to not be performed concurrently with anything else on that queue). This can offer a performance improvement over a simple GCD serial solution, but in practice, the advantage is modest and comes at the cost of additional complexity (e.g., you have to be careful about thread-explosion scenarios). IMHO, I tend to avoid this pattern, either sticking with the simplicity of the serial queue pattern, or, when the performance difference is critical, using a completely different pattern. Locks: In my Swift tests, lock-based synchronization tends to be substantially faster than either of the GCD approaches. Locks come in a few flavors: NSLock is a nice, relatively efficient lock mechanism. In those cases where performance is of paramount concern, I use “unfair locks”, but you must be careful when using them from Swift (see https://stackoverflow.com/a/66525671/1271826). For the sake of completeness, there is also the recursive lock. IMHO, I would favor simple NSLock over NSRecursiveLock. Recursive locks are subject to abuse and often indicate code smell. You might see references to “spin locks”. Many years ago, they used to be employed where performance was of paramount concern, but they are now deprecated in favor of unfair locks. Technically, one can use semaphores for synchronization, but it tends to be the slowest of all the alternatives.
我在这里概述了我的一些基准测试结果。
简而言之,现在我在当代代码库中使用actor,在简单的非异步等待代码中使用GCD串行队列,在性能至关重要的极少数情况下使用锁。
不用说,我们经常尝试减少同步的数量。如果可以,我们通常使用值类型,其中每个线程获得自己的副本。在无法避免同步的情况下,我们会尽量减少同步的数量。
在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线程来实现它的锁定行为。当向NSLock对象发送解锁消息时,必须确保该消息是从发送初始锁定消息的同一个线程发送的。从不同的线程解锁锁可能会导致未定义的行为。
斯威夫特4
在Swift 4中,你可以使用gcd调度队列来锁定资源。
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 }
}
}
}
你可以把语句夹在objc_sync_enter(obj: AnyObject?)和objc_sync_exit(obj: AnyObject?)之间。@synchronized关键字在幕后使用这些方法。即。
objc_sync_enter(self)
... synchronized code ...
objc_sync_exit(self)
使用Bryan McLemore的答案,我扩展了它,以支持使用Swift 2.0延迟能力扔进安全庄园的对象。
func synchronized( lock:AnyObject, block:() throws -> Void ) rethrows
{
objc_sync_enter(lock)
defer {
objc_sync_exit(lock)
}
try block()
}
推荐文章
- 如何停止不必要的UIButton动画标题变化?
- 如何使用Swift播放声音?
- 如何解散ViewController在Swift?
- 保存字符串到NSUserDefaults?
- 如何将JSON字符串转换为字典?
- 什么是NSLocalizedString等效在Swift?
- 如何创建一个字符串的格式?
- 获取最顶端的UIViewController
- 使用isKindOfClass与Swift
- SourceKitService终止
- 我如何在Swift中解析/创建一个以分数秒UTC时区(ISO 8601, RFC 3339)格式化的日期时间戳?
- 如何使用@Binding变量实现自定义初始化
- Swift设置为Array
- 如何设置回退按钮文本在Swift
- 我如何能在Swift扩展类型化数组?