Last active
May 31, 2020 17:54
-
-
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/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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