Skip to content

Instantly share code, notes, and snippets.

@lukaskukacka
Last active May 12, 2019 20:20
Show Gist options
  • Save lukaskukacka/f24bf9a855f35a69cef4a22ae94c908d to your computer and use it in GitHub Desktop.
Save lukaskukacka/f24bf9a855f35a69cef4a22ae94c908d to your computer and use it in GitHub Desktop.
Simple Swift generic wrapper class giving synchronized (threadsafe) access to an instance (Swift 5)
// Swift Playground
import Foundation
import Dispatch
final class Synchronized<T> {
private let queue: DispatchQueue
private var _value: T
init(_ value: T) {
let queueLabel = "com.lukaskukacka.synchronized.\(type(of: value)).\(UUID().uuidString)"
self.queue = DispatchQueue(label: queueLabel, attributes: .concurrent)
self._value = value
}
var value: T {
var result: T? = nil
queue.sync { result = self._value }
return result!
}
func write(using block: @escaping (inout T) -> Void) {
queue.async(flags: .barrier) {
block(&self._value)
}
}
}
// MARK: - Tests
let numberOfIterations = 200
func measure(block: () -> Void) {
let startDate = Date()
block()
let duration: TimeInterval = Date().timeIntervalSince(startDate)
print(String(format: "Task took %.5fs", duration))
}
print("# Race condition")
measure {
var unsafeArray = [Int]()
DispatchQueue.concurrentPerform(iterations: numberOfIterations) { index in
let last = unsafeArray.last ?? 0
unsafeArray.append(last + 1)
}
print(unsafeArray)
}
print("# Synchronized")
measure {
let synchronizedArray: Synchronized<[Int]> = Synchronized([])
DispatchQueue.concurrentPerform(iterations: numberOfIterations) { index in
synchronizedArray.write {
let last = $0.last ?? 0
$0.append(last + 1)
}
}
print(synchronizedArray.value)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment