ProgramGuru

Structured concurrency and cancellation

Structured concurrency and cancellation

A report can request two independent values before combining them. Structured concurrency keeps child work tied to a scope. That scope waits for its children and organizes failure and cancellation rather than leaving forgotten work running without a clear owner.

What you’ll learn

  • Await independent structured children.
  • Distinguish scheduling, cancellation and result dependencies.

Structured concurrency and cancellation in the example

  1. Start children

    A report can request two independent values before combining them.

    Start children
  2. Await both results

    Async returns a Deferred result; await retrieves it when available.

    Await both results
  3. Combine total

    Two children start before their results are combined.

    Combine total
Two children start before their results are combined. The total is 170 regardless of their internal completion order because both fixed values are awaited. The tiny simulated delays do not establish a useful speed benchmark.

Understand structured concurrency and cancellation

Async returns a Deferred result; await retrieves it when available. Launch is intended for work whose returned value is not needed in that form. CoroutineScope establishes the structured child relationship. Cancellation is cooperative and should be checked or reached through cancellable operations.

Connect this to lambdas and higher-order functions and exceptions and deliberate failure handling.

Follow structured concurrency and cancellation

Save the complete source as Main.kt and use the Kotlin/JVM environment. Use a local Kotlin/JVM project with org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2. This example requires the library on both compile and runtime classpaths. See coroutine setup.

Kotlin/JVM · complete program

import kotlinx.coroutines.*
suspend fun totalScore(): Int = coroutineScope {
  val first = async { delay(1); 80 }
  val second = async { delay(1); 90 }
  first.await() + second.await()
}
fun main() = runBlocking { println("Total: ${totalScore()}") }

Expected output

Total: 170

Follow the execution

Two children start before their results are combined. The total is 170 regardless of their internal completion order because both fixed values are awaited. The tiny simulated delays do not establish a useful speed benchmark.

Practice: Structured concurrency and cancellation

Your task: Can you infer the first child finished first from its declaration order?

Kotlin/JVM · complete program

import kotlinx.coroutines.*
suspend fun totalScore(): Int = coroutineScope {
  val first = async { delay(1); 80 }
  val second = async { delay(1); 90 }
  first.await() + second.await()
}
fun main() = runBlocking { println("Total: ${totalScore()}") }

Worked answer

No. Independent completion order is not guaranteed. Await the values or coordinate an actual ordering requirement explicitly.

Structured concurrency and cancellation: the important boundary

Propagate CancellationException rather than hiding cancellation in a broad catch. Supervisor scopes have different failure relationships, and dispatchers do not make shared mutable data atomic. Avoid GlobalScope as an unexplained lifetime shortcut.

Check your understanding

Can you infer the first child finished first from its declaration order?
Choose one answer. You can try again.

Answer and explanation

No.

No. Independent completion order is not guaranteed. Await the values or coordinate an actual ordering requirement explicitly.

Check the practical consequence

A coroutine is cancelled while waiting. What should ordinary cancellation handling do?
Choose one answer. You can try again.

Answer and explanation

Preserve cancellation propagation rather than swallowing it as a successful result.

Await independent structured children. Distinguish scheduling, cancellation and result dependencies.

Structured concurrency and cancellation: what to keep in mind

No. Independent completion order is not guaranteed. Await the values or coordinate an actual ordering requirement explicitly. Propagate CancellationException rather than hiding cancellation in a broad catch.

Further reading: official Kotlin documentation for this topic.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: Flows and safe shared state →