Skip to content

Instantly share code, notes, and snippets.

@JadenGeller
Created November 17, 2023 19:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JadenGeller/ffb6c31ef1d81a69f1302d8fc4f1867a to your computer and use it in GitHub Desktop.
Save JadenGeller/ffb6c31ef1d81a69f1302d8fc4f1867a to your computer and use it in GitHub Desktop.
Semaphore using Swift async
actor Semaphore {
private var capacity: Int {
didSet {
assert(capacity >= 0)
}
}
struct Waiter {
var priority: TaskPriority
var continuation: CheckedContinuation<Void, Never>
}
private var waiters: [Waiter] = []
init(capacity: Int = 0) {
self.capacity = capacity
}
func wait() async {
if capacity > 0 {
capacity -= 1
} else {
let priority = Task.currentPriority
await withCheckedContinuation { waiters.append(.init(priority: priority, continuation: $0)) }
}
}
func signal() {
if waiters.isEmpty {
capacity += 1
} else {
// FIXME: prioritize higher priority tasks before lower priority tasks!
waiters.removeFirst().continuation.resume()
}
}
func withCriticalSection<Result>(_ runCriticalSection: () async -> Result) async -> Result {
await wait()
defer { signal() }
return await runCriticalSection()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment