ReadWriteLock is a lightweight framework of a safe an easy implementation of a read-write lock for iOS, macOS, tvOS, and watchOS.
ReadWriteLock is available through CocoaPods, Carthage and the Swift Package Manager.
To install via CocoaPods, simply add the following line to your Podfile:
pod 'ReadWriteLock'
To install via Carthage, simply add the following line to your Cartfile:
github "SomeRandomiOSDev/ReadWriteLock"
To install via the Swift Package Manager add the following line to your Package.swift
file's dependencies
:
.package(url: "https://github.com/SomeRandomiOSDev/ReadWriteLock.git", from: "1.0.0")
First import ReadWriteLock at the top of your Swift file:
import ReadWriteLock
After importing simply instantiate a ReadWriteLock
instance and start acquiring locks:
let lock = ReadWriteLock()
var protectedResource = ...
DispatchQueue.global(qos: .background).async {
...
lock.acquireWriteLock {
protectedResource = ...
}
}
...
DispatchQueue.global(qos: .background).async {
...
lock.acquireReadLock {
process(protectedResource)
}
}
Or you can conditionally attempt to acquire a lock. Acquiring a lock in this way will not block if the lock has already been claimed:
...
lock.attemptAcquireReadLock { isLockAcquired in
if isLockAcquired {
process(protectedResource)
} else {
// `lock` is currently locked for writing.
}
}
Acquiring locks uses Swift closures to scope the lifetime of the read/write lock. This prevents lingering locks when the ReadWriteLock
object is deallocated and helps prevent deadlocks. Note that if you attempt to acquire a write lock from inside of the scope of an already acquired read or write lock, or acquiring a read lock from inside of the scope of an already acquired write lock, the thread will deadlock:
// All of these code blocks will deadlock
lock.acquireWriteLock {
...
lock.acquireWriteLock {
// deadlock
}
}
lock.acquireReadLock {
...
lock.acquireWriteLock {
// deadlock
}
}
lock.attemptAcquireWriteLock { isLockAcquired in
...
if isLockAcquired {
lock.acquireWriteLock {
// deadlock
}
}
}
...
The benefit of read/write locks over traditional locks is that you may have (virtually) unlimited read locks, even nested read locks, without deadlocking:
lock.acquireReadLock {
...
lock.acquireReadLock {
// won't deadlock
}
lock.attemptAcquireReadLock { isLockAcquired in
// isLockAcquired is `true`
}
}
Read/write locks are ideal for synchronizing access to properties:
struct SynchronizedValue<T> {
private var lock = ReadWriteLock()
private var _value: T
var value: T {
get {
return lock.acquireReadLock { _value }
}
set {
lock.acquireWriteLock { _value = newValue }
}
}
}
If you have need for a specific feature or you encounter a bug, please open an issue. If you extend the functionality of ReadWriteLock yourself or you feel like fixing a bug yourself, please submit a pull request.
Joe Newton, somerandomiosdev@gmail.com
ReadWriteLock is available under the MIT license. See the LICENSE
file for more info.