-
-
Save macguru/9b9b42fabcd72c1613b060bb12ee0344 to your computer and use it in GitHub Desktop.
| import Synchronization | |
| func untilCancelled() async { | |
| print("1") | |
| let mutex: Mutex<CheckedContinuation<Void, Never>?> = .init(nil) | |
| await withTaskCancellationHandler { | |
| print("2") | |
| await withCheckedContinuation { continuation in | |
| print("3") | |
| mutex.withLock { | |
| if Task.isCancelled { | |
| print("abort") | |
| continuation.resume() | |
| return | |
| } | |
| print("4") | |
| $0 = continuation | |
| } | |
| } | |
| } onCancel: { | |
| let continuation = mutex.withLock { | |
| print("5") | |
| return $0.take() | |
| } | |
| continuation?.resume() | |
| } | |
| print("6") | |
| } | |
| func main() async throws { | |
| let hangsForever = Task { | |
| await untilCancelled() | |
| } | |
| // Comment out this line to test early cancellation. | |
| try await Task.sleep(for: .milliseconds(10)) | |
| print("will cancel") | |
| hangsForever.cancel() | |
| print("did cancel") | |
| try await Task.sleep(for: .milliseconds(10)) | |
| } | |
| try await main() |
@Noobish1 About your example… I'm wondering what the perform() would be doing. Because for anything "heavy" you'd probably want an asynchronous context, so you'd need to make a task there. And then, you could leave out the continuation handling entirely and just wrap what you're doing in a cancellation handler.
@EngOmarElsayed I'm not entirely sure what you mean in the reference to the forum post you liked. But if I understand you correctly, then in those cases where you have a Task, you don't need any of the dance here. I talked about this in my post under The simple example.
@macguru perform would be some API that uses closure callbacks that can't be easily converted to async/await.
var thisIsNotActuallySafe: NonSendable { locked.withLock { $0 } }
But why this isn't safe, I think there is something I am missing but what is it 😅 ?
I'm not entirely sure what you mean in the reference to the forum post you liked. But if I understand you correctly, then in those cases where you have a
Task, you don't need any of the dance here. I talked about this in my post under The simple example.
You are right, I was sharing something I found with you 😅
But why this isn't safe, I think there is something I am missing but what is it 😅 ?
This type, as implemented, makes it possible to send non-Sendable data. That doesn't mean it actually will happen, just that the compiler will not be able to prevent it.
But why this isn't safe, I think there is something I am missing but what is it 😅 ?
This type, as implemented, makes it possible to send non-Sendable data. That doesn't mean it actually will happen, just that the compiler will not be able to prevent it.
Got you, thanks for the explanation
@EngOmarElsayed we’ve been using this package for a legacy mutex: https://github.com/swhitty/swift-mutex