Skip to content

Instantly share code, notes, and snippets.

@suhitp
Last active August 23, 2020 19:18
Show Gist options
  • Save suhitp/79720cc53c32351eb404e5d3c5030596 to your computer and use it in GitHub Desktop.
Save suhitp/79720cc53c32351eb404e5d3c5030596 to your computer and use it in GitHub Desktop.
// MARK: Lock Protocol
protocol Lock: AnyObject {
/// locks the resource to execute action
func lock()
/// unlocks the resource
func unlock()
}
extension Lock {
/// Executes a closure returning a value while acquiring the lock.
/// - Parameter closure: The closure to run.
/// - Returns: The value the closure generated.
func readAction<T>(_ closure: () -> T) -> T {
lock(); defer { unlock() }
return closure()
}
/// Execute a closure while acquiring the lock.
/// - Parameter closure: The closure to run.
func writeAction(_ closure: () -> Void) {
lock(); defer { unlock() }
closure()
}
}
final class ThreadSafeLock: Lock {
private lazy var unfairLock = os_unfair_lock_s()
private lazy var _lock = NSLock()
func lock() {
if #available(iOS 10.0, *) {
os_unfair_lock_lock(&unfairLock)
} else {
_lock.lock()
}
}
func unlock() {
if #available(iOS 10.0, *) {
os_unfair_lock_unlock(&unfairLock)
} else {
_lock.unlock()
}
}
}
@propertyWrapper
final class ThreadSafeProperty<T> {
private var value: T
private let lock = ThreadSafeLock()
init(wrappedValue: T) {
self.value = wrappedValue
}
/// The contained value. Unsafe for anything more than direct read or write.
var wrappedValue: T {
get { lock.readAction { value } }
set { lock.writeAction { value = newValue } }
}
var projectedValue: ThreadSafeProperty<T> { self }
/// Synchronously read or transform the contained value.
/// - Parameter closure: The closure to execute.
/// - Returns: The return value of the closure passed.
func read<U>(_ closure: (T) -> U) -> U {
return lock.readAction { closure(self.value) }
}
/// Synchronously modify the protected value.
/// - Parameter closure: The closure to execute.
/// - Returns: The modified value.
func write<U>(_ closure: (inout T) -> U) -> Void {
lock.readAction { closure(&self.value) }
}
}
@suhitp
Copy link
Author

suhitp commented Jun 7, 2020

struct ThreadSafePropertyTest {

    @ThreadSafeProperty var values: [Int] = []

    mutating func appendValues() {
      DispatchQueue.concurrentPerform(iterations: 100) { value in
        $values.write { (values: inout [Int]) in
            values.append(value)
        }
      }
    }
}

var t = ThreadSafePropertyTest()
t.appendValues()
print(t.values)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment