Quick answer: Godot 4 C# CancellationToken.Cancel() blocking the main thread when called from a signal handler? Cancel runs callbacks synchronously; long callbacks freeze the engine - use CancellationTokenSource.CancelAsync.

Network task cancel takes 800ms because the registered callback runs inline.

Use CancelAsync

await cts.CancelAsync();

Available .NET 8+. Callbacks run on a thread pool task; main thread returns immediately.

Or detach the callback

Register cancellation handlers on a Task.Run wrapper. The detach moves the work off the main thread.

Audit registered callbacks

Cancel callbacks should be short. Anything > 1ms belongs on a worker.

“Cancellation callbacks run somewhere. Default is somewhere is the caller's thread.”

Build a cancellation helper that wraps token sources with async cancel + worker dispatch. Misuse-resistant.

Related reading