Created
November 17, 2023 19:09
-
-
Save JadenGeller/ffb6c31ef1d81a69f1302d8fc4f1867a to your computer and use it in GitHub Desktop.
Semaphore using Swift async
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
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