mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Concurrency] Cancelled group should only spawn already cancelled tasks
This commit is contained in:
@@ -39,6 +39,9 @@ public:
|
||||
|
||||
/// Upon a future task's completion, offer it to the task group it belongs to.
|
||||
void offer(AsyncTask *completed, AsyncContext *context);
|
||||
|
||||
/// Checks the cancellation status of the group.
|
||||
bool isCancelled();
|
||||
};
|
||||
|
||||
} // end namespace swift
|
||||
|
||||
@@ -565,7 +565,8 @@ static AsyncTaskAndContext swift_task_create_group_future_commonImpl(
|
||||
// In a task group we would not have allowed the `add` to create a child anymore,
|
||||
// however better safe than sorry and `async let` are not expressed as task groups,
|
||||
// so they may have been spawned in any case still.
|
||||
if (swift_task_isCancelled(parent))
|
||||
if (swift_task_isCancelled(parent) ||
|
||||
(group && group->isCancelled()))
|
||||
swift_task_cancel(task);
|
||||
|
||||
// Initialize task locals with a link to the parent task.
|
||||
|
||||
@@ -508,6 +508,10 @@ void TaskGroup::offer(AsyncTask *completedTask, AsyncContext *context) {
|
||||
asImpl(this)->offer(completedTask, context);
|
||||
}
|
||||
|
||||
bool TaskGroup::isCancelled() {
|
||||
return asImpl(this)->isCancelled();
|
||||
}
|
||||
|
||||
static void fillGroupNextResult(TaskFutureWaitAsyncContext *context,
|
||||
PollResult result) {
|
||||
/// Fill in the result value
|
||||
|
||||
@@ -355,12 +355,12 @@ public struct TaskGroup<ChildTaskResult> {
|
||||
_taskGroupIsEmpty(_group)
|
||||
}
|
||||
|
||||
/// Cancel all the remaining tasks in the group.
|
||||
/// Cancel all the remaining, and future, tasks in the group.
|
||||
///
|
||||
/// A cancelled group will not will NOT accept new tasks being added into it.
|
||||
///
|
||||
/// Any results, including errors thrown by tasks affected by this
|
||||
/// cancellation, are silently discarded.
|
||||
/// A cancelled group will not will create new tasks when the `asyncUnlessCancelled`,
|
||||
/// function is used. It will, however, continue to create tasks when the plain `async`
|
||||
/// function is used. Such tasks will be created yet immediately cancelled, allowing
|
||||
/// the tasks to perform some short-cut implementation, if they are responsive to cancellation.
|
||||
///
|
||||
/// This function may be called even from within child (or any other) tasks,
|
||||
/// and will reliably cause the group to become cancelled.
|
||||
|
||||
@@ -37,13 +37,16 @@ func test_taskGroup_cancel_then_add() async {
|
||||
let none = await group.next()
|
||||
print("next second: \(none)") // CHECK: next second: nil
|
||||
|
||||
group.spawn { 3 }
|
||||
print("added third, unconditionally") // CHECK: added third, unconditionally
|
||||
print("group isCancelled: \(group.isCancelled)") // CHECK: group isCancelled: true
|
||||
|
||||
group.spawn {
|
||||
print("child task isCancelled: \(Task.isCancelled)") // CHECK: child task isCancelled: true
|
||||
return 3
|
||||
}
|
||||
let three = await group.next()!
|
||||
print("next third: \(three)") // CHECK: next third: 3
|
||||
|
||||
print("added third, unconditionally") // CHECK: added third, unconditionally
|
||||
print("group isCancelled: \(group.isCancelled)") // CHECK: group isCancelled: true
|
||||
|
||||
return one + (none ?? 0)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user