@@ -144,7 +144,7 @@ public actor QueuedTask<TaskDescription: TaskDescriptionProtocol> {
144144 /// Whether `cancelToBeRescheduled` has been called on this `QueuedTask`.
145145 ///
146146 /// Gets reset every time `executionTask` finishes.
147- nonisolated ( unsafe ) private var cancelledToBeRescheduled : AtomicBool = . init ( initialValue : false )
147+ private var cancelledToBeRescheduled : Bool = false
148148
149149 /// Whether `resultTask` has been cancelled.
150150 private nonisolated ( unsafe) var resultTaskCancelled: AtomicBool = . init( initialValue: false )
@@ -228,6 +228,15 @@ public actor QueuedTask<TaskDescription: TaskDescriptionProtocol> {
228228 /// Execution might be canceled to be rescheduled, in which case this returns `.cancelledToBeRescheduled`. In that
229229 /// case the `TaskScheduler` is expected to call `execute` again.
230230 func execute( ) async -> ExecutionTaskFinishStatus {
231+ if cancelledToBeRescheduled {
232+ // `QueuedTask.execute` is called from a detached task in `TaskScheduler.poke` but we insert it into the
233+ // `currentlyExecutingTasks` queue beforehand. This leaves a short windows in which we could cancel the task to
234+ // reschedule it before it actually starts executing.
235+ // If this happens, we don't have to do anything in `execute` and can immediately return. `execute` will be called
236+ // again when the task gets rescheduled.
237+ cancelledToBeRescheduled = false
238+ return . cancelledToBeRescheduled
239+ }
231240 precondition ( executionTask == nil , " Task started twice " )
232241 let task = Task . detached ( priority: self . priority) {
233242 if !Task. isCancelled && !self . resultTaskCancelled. value {
@@ -246,9 +255,9 @@ public actor QueuedTask<TaskDescription: TaskDescriptionProtocol> {
246255 private func finalizeExecution( ) async -> ExecutionTaskFinishStatus {
247256 self . executionTask = nil
248257 _isExecuting. value = false
249- if Task . isCancelled && self . cancelledToBeRescheduled. value {
258+ if Task . isCancelled && self . cancelledToBeRescheduled {
250259 await executionStateChangedCallback ? ( self , . cancelledToBeRescheduled)
251- self . cancelledToBeRescheduled. value = false
260+ self . cancelledToBeRescheduled = false
252261 return ExecutionTaskFinishStatus . cancelledToBeRescheduled
253262 } else {
254263 await executionStateChangedCallback ? ( self , . finished)
@@ -260,10 +269,10 @@ public actor QueuedTask<TaskDescription: TaskDescriptionProtocol> {
260269 ///
261270 /// If the task has not been started yet or has already finished execution, this is a no-op.
262271 func cancelToBeRescheduled( ) {
272+ self . cancelledToBeRescheduled = true
263273 guard let executionTask else {
264274 return
265275 }
266- self . cancelledToBeRescheduled. value = true
267276 executionTask. cancel ( )
268277 self . executionTask = nil
269278 }
0 commit comments