Skip to content

Commit 59719fb

Browse files
committed
document cancellation in more depth on discarding group too
1 parent 926c0bb commit 59719fb

File tree

2 files changed

+38
-20
lines changed

2 files changed

+38
-20
lines changed

stdlib/public/Concurrency/DiscardingTaskGroup.swift

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,11 @@ public func withDiscardingTaskGroup<GroupResult>(
116116
/// be the case with a ``TaskGroup``.
117117
///
118118
/// ### Cancellation behavior
119-
/// A task group becomes cancelled in one of two ways: when ``cancelAll()`` is
120-
/// invoked on it, or when the ``Task`` running this task group is cancelled.
119+
/// A discarding task group becomes cancelled in one of the following ways:
120+
///
121+
/// - when ``cancelAll()`` is invoked on it,
122+
/// - when an error is thrown out of the `withThrowingDiscardingTaskGroup(...) { }` closure,
123+
/// - when the ``Task`` running this task group is cancelled.
121124
///
122125
/// Since a `TaskGroup` is a structured concurrency primitive, cancellation is
123126
/// automatically propagated through all of its child-tasks (and their child
@@ -431,8 +434,28 @@ public func withThrowingDiscardingTaskGroup<GroupResult>(
431434
/// be the case with a ``TaskGroup``.
432435
///
433436
/// ### Cancellation behavior
434-
/// A task group becomes cancelled in one of two ways: when ``cancelAll()`` is
435-
/// invoked on it, or when the ``Task`` running this task group is cancelled.
437+
/// A throwing discarding task group becomes cancelled in one of the following ways:
438+
///
439+
/// - when ``cancelAll()`` is invoked on it,
440+
/// - when an error is thrown out of the `withThrowingDiscardingTaskGroup(...) { }` closure,
441+
/// - when the ``Task`` running this task group is cancelled.
442+
///
443+
/// But also, and uniquely in *discarding* task groups:
444+
/// - when *any* of its child tasks throws.
445+
///
446+
/// The group becoming cancelled automatically, and cancelling all of its child tasks,
447+
/// whenever *any* child task throws an error is a behavior unique to discarding task groups,
448+
/// because achieving such semantics is not possible otherwise, due to the missing `next()` method
449+
/// on discarding groups. Accumulating task groups can implement this by manually polling `next()`
450+
/// and deciding to `cancelAll()` when they decide an error should cause the group to become cancelled,
451+
/// however a discarding group cannot poll child tasks for results and therefore assumes that child
452+
/// task throws are an indication of a group wide failure. In order to avoid such behavior,
453+
/// use a ``DiscardingTaskGroup`` instead of a throwing one, or catch specific errors in
454+
/// operations submitted using `addTask`
455+
///
456+
/// Since a `TaskGroup` is a structured concurrency primitive, cancellation is
457+
/// automatically propagated through all of its child-tasks (and their child
458+
/// tasks).
436459
///
437460
/// Since a `TaskGroup` is a structured concurrency primitive, cancellation is
438461
/// automatically propagated through all of its child-tasks (and their child
@@ -524,6 +547,7 @@ public struct ThrowingDiscardingTaskGroup<Failure: Error> {
524547
#endif
525548
}
526549

550+
///
527551
public var isEmpty: Bool {
528552
_taskGroupIsEmpty(_group)
529553
}

stdlib/public/Concurrency/TaskGroup.swift

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -218,15 +218,12 @@ public func withThrowingTaskGroup<ChildTaskResult, GroupResult>(
218218
/// Tasks added to a task group execute concurrently, and may be scheduled in
219219
/// any order.
220220
///
221-
/// ### Discarding behavior
222-
/// A discarding task group eagerly discards and releases its child tasks as
223-
/// soon as they complete. This allows for the efficient releasing of memory used
224-
/// by those tasks, which are not retained for future `next()` calls, as would
225-
/// be the case with a ``TaskGroup``.
226-
///
227221
/// ### Cancellation behavior
228-
/// A task group becomes cancelled in one of two ways: when ``cancelAll()`` is
229-
/// invoked on it, or when the ``Task`` running this task group is cancelled.
222+
/// A task group becomes cancelled in one of the following ways:
223+
///
224+
/// - when ``cancelAll()`` is invoked on it,
225+
/// - when an error is thrown out of the `withTaskGroup(...) { }` closure,
226+
/// - when the ``Task`` running this task group is cancelled.
230227
///
231228
/// Since a `TaskGroup` is a structured concurrency primitive, cancellation is
232229
/// automatically propagated through all of its child-tasks (and their child
@@ -558,15 +555,12 @@ extension TaskGroup: Sendable { }
558555
/// Tasks added to a task group execute concurrently, and may be scheduled in
559556
/// any order.
560557
///
561-
/// ### Discarding behavior
562-
/// A discarding task group eagerly discards and releases its child tasks as
563-
/// soon as they complete. This allows for the efficient releasing of memory used
564-
/// by those tasks, which are not retained for future `next()` calls, as would
565-
/// be the case with a ``TaskGroup``.
566-
///
567558
/// ### Cancellation behavior
568-
/// A task group becomes cancelled in one of two ways: when ``cancelAll()`` is
569-
/// invoked on it, or when the ``Task`` running this task group is cancelled.
559+
/// A task group becomes cancelled in one of the following ways:
560+
///
561+
/// - when ``cancelAll()`` is invoked on it,
562+
/// - when an error is thrown out of the `withThrowingTaskGroup(...) { }` closure,
563+
/// - when the ``Task`` running this task group is cancelled.
570564
///
571565
/// Since a `TaskGroup` is a structured concurrency primitive, cancellation is
572566
/// automatically propagated through all of its child-tasks (and their child

0 commit comments

Comments
 (0)