I have the following 2 thread safe wrappers implementation for a boolean:
1 - Using NSLock
class ThreadSafeBool {
private let lock = NSLock()
private var wrappedValue: Bool
var value: Bool {
get {
lock.lock()
defer { lock.unlock() }
return wrappedValue
}
set {
lock.lock()
defer { lock.unlock() }
wrappedValue = newValue
}
}
init(_ initialValue: Bool) {
wrappedValue = initialValue
}
}
2 - Using DispatchQueue and sync
class ThreadSafeBoolQueue {
private let queue = DispatchQueue(label: "my.queue")
private var wrappedValue: Bool
var value: Bool {
get {
self.queue.sync { return wrappedValue }
}
set {
self.queue.sync { wrappedValue = newValue }
}
}
init(_ initialValue: Bool) {
wrappedValue = initialValue
}
}
Even though the NSLock it is much more faster then the sync queues, os_unfair_lock
is even faster.
Could someone please let me know why in lots of example is prefer the second locking mode, including Apple presentation?
PS: Please keep in mind that the classes are just examples, so the main question is why queue over NSLock/os_unfair_lock?
Thank you very much
Could someone please let me know why in lots of example is prefer the second locking mode, including Apple presentation?
It’s mostly for historical reasons. When Dispatch was first introduced folks went ‘Dispatch happy’ and started using it for everything. This wasn’t helped by Apple’s documentation not being clear about this issue.
If you’re curious about Apple’s current thinking on this topic — and there’s a lot of emphasis on unfair lock! — watch WWDC 2017 Session 706 Modernizing Grand Central Dispatch Usage.
Personally I tend to use NSLock
and will continue to do so until I’m able to rely on OSAllocatedUnfairLock
being available. Using os_unfair_lock
from Swift more hassle that it’s worth in most cases [1].
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
[1] Because you need to manually manage memory due to the issue discussed in The Peril of the Ampersand.