chapter two

2 Concurrency

 

This chapter covers

  • Distinguishing between Concurrency (structure) and Parallelism (execution)
  • Using Coroutines for cooperative multitasking within a single thread
  • Managing shared resources with Mutexes and Semaphores
  • Identifying the difference between Data Races and Race Conditions

In modern software development, handling multiple tasks efficiently isn't just a performance optimization — it's often a functional requirement. Whether you're building a high-throughput backend service or a responsive user interface, you need to know how to structure concurrent work. But concurrency introduces its own class of complexity: race conditions, unpredictable timing, and resource contention. This chapter demystifies the core concepts, moving past the syntax to the primitives that let you write safe, non-blocking code.

We'll start with the distinction that trips up most developers — concurrency versus parallelism — using a coffee shop as our running example, and we'll keep coming back to it throughout the chapter. From there we move to coroutines, which give us concurrency without parallelism. Then to mutexes and semaphores, the two primitives most commonly used to coordinate access to shared resources. We close with the difference between a data race and a race condition — a distinction worth getting right, because eliminating one doesn't eliminate the other.

2.1 Concurrency vs. Parallelism

2.1.1 Differences

2.1.2 FAQ

2.2 Coroutines

2.3 Mutex vs. Semaphore

2.4 Data Race vs. Race Condition

2.5 Summary