-
Notifications
You must be signed in to change notification settings - Fork 0
19 — Cancellation in GCD
Yelling "cancel that order!" only works if the chef hasn't started cooking yet. Once it's on the grill, someone has to actively notice and stop — nobody stops it for them.
GCD has no built-in structured cancellation. DispatchWorkItem.cancel() only prevents execution if the block hasn't started yet — it cannot interrupt work already running. To support mid-execution cancellation, the block itself must cooperatively check item.isCancelled at safe points.
Not started yet: [ticket] ──cancel()──▶ 🗑️ torn up, never cooked
Already on grill: [ticket] ──cancel()──▶ 🔥 still cooking, unaffected
var item: DispatchWorkItem!
item = DispatchWorkItem {
for i in 0..<1_000_000 {
if item.isCancelled { return } // must check cooperatively at safe points
doChunkOfWork(i)
}
}
queue.async(execute: item)
item.cancel() // only effective if `item` hasn't started running yet👉 Once item has started executing, calling .cancel() sets a flag but does nothing to stop the loop already in progress — the block only bails out early because it checks item.isCancelled itself, between chunks.
Task cancellation is also cooperative, but it's first-class throughout the ecosystem — Task.isCancelled, Task.checkCancellation(), and cancellation propagating automatically to child tasks in a TaskGroup or async let.
Cancellation only works before the order hits the grill — after that, someone has to check.
GCD gives you no structural help propagating a cancellation signal to related work the way Swift Concurrency's task trees do — you'd have to build that bookkeeping yourself.
Why doesn't calling .cancel() on a DispatchWorkItem that's already executing stop it?