Skip to content

Instantly share code, notes, and snippets.

@khurram18
Last active May 31, 2020 17:54
Show Gist options
  • Save khurram18/870a94a41879bfad646d7fd7a7cbfa26 to your computer and use it in GitHub Desktop.
Save khurram18/870a94a41879bfad646d7fd7a7cbfa26 to your computer and use it in GitHub Desktop.
Different approaches for implementing atomic types in swift. Please see the complete article here https://swiftx.tech/atomics-types-in-swift/
// A protocol to be used in our atomic type
protocol Operatable {
func add(other: Self) -> Self
}
// We will only limit our atomic type to Int, but it can be extended to use any other type
extension Int: Operatable {
func add(other: Int) -> Int {
return self + other
}
}
final class Atomic<T: Operatable> {
private var t: T
init(_ t: T) {
self.t = t
}
func incrementAndGet(by other: T) -> T {
// Critical section starts
// The change to t should be atomic here
print("\(Thread.current.name!): critical section started")
let result = t.add(other: other)
t = result
print("\(Thread.current.name!): critical section ended")
// Critical section ends
return result
}
}
final class NSAtomic<T: Operatable> {
private var t: T
let locl = NSLock()
init(_ t: T) {
self.t = t
}
func incrementAndGet(by other: T) -> T {
// Critical section starts
// The change to t should be atomic here
locl.lock()
print("\(Thread.current.name!): critical section started")
let result = t.add(other: other)
t = result
print("\(Thread.current.name!): critical section ended")
locl.unlock()
// Critical section ends
return result
}
}
final class GCDAtomic<T: Operatable> {
private let initial: T
private var t: T
let dispatchQueue = DispatchQueue(label: "tech.swiftx.dispatchQueue")
init(_ t: T) {
self.t = t
initial = t
}
func incrementAndGet(by other: T) -> T {
var result = initial
dispatchQueue.sync {
// Critical section starts
// The change to t should be atomic here
print("\(Thread.current.name!): critical section started")
result = t.add(other: other)
t = result
print("\(Thread.current.name!): critical section ended")
// Critical section ends
}
return result
}
}
func testAtomic() {
print("test without any synchronization ")
let atomicInt = Atomic<Int>(0)
for i in 1...5 {
let thread = Thread {
_ = atomicInt.incrementAndGet(by: 1)
}
thread.name = "Thread: \(i)"
thread.start()
}
Thread.sleep(forTimeInterval: 2)
}
func testNSAtomic() {
print("test with NSLock")
let atomicInt = NSAtomic<Int>(0)
for i in 1...5 {
let thread = Thread {
_ = atomicInt.incrementAndGet(by: 1)
}
thread.name = "Thread: \(i)"
thread.start()
}
Thread.sleep(forTimeInterval: 2)
}
func testGCDAtomic() {
print("test with GCD")
let atomicInt = GCDAtomic<Int>(0)
for i in 1...5 {
let thread = Thread {
_ = atomicInt.incrementAndGet(by: 1)
}
thread.name = "Thread: \(i)"
thread.start()
}
Thread.sleep(forTimeInterval: 2)
}
testAtomic()
testNSAtomic()
testGCDAtomic()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment