Sendable Closures that are also isolated and synchronous?

In this sample:

func isMainThread() -> Bool {
    return Thread.isMainThread
}

let task = Task.detached {
    await withTaskCancellationHandler(
        operation: { @MainActor in
            print("operation() started -> isMainActor: \(isMainThread()), thread: \(pthread_self())")
            try? await Task.sleep(for: .seconds(2))
            print("operation() finished -> isMainActor: \(isMainThread()), thread: \(pthread_self())")
        },
        onCancel: {
            print("onCancel() -> isMainActor: \(isMainThread()), thread: \(pthread_self())")
        },
        isolation: MainActor.shared
    )
}

await Task.detached {
    try? await Task.sleep(for: .seconds(1))
    print("cancel() -> isMainActor: \(isMainThread()), thread: \(pthread_self())")
    task.cancel()
}.value

I get this output:

operation() started -> isMainActor: true, thread: 0x202e105c0
cancel() -> isMainActor: false, thread: 0x16fe87000
onCancel() -> isMainActor: false, thread: 0x16fe87000
operation() finished -> isMainActor: true, thread: 0x202e105c0

Which makes sense: the Main Actor can't execute both operation and onCancel concurrently.

You can also see that cancel() and onCancel happen on the same thread.

3 Likes