Programming in C++

Concurrency and Parallelism

Overview

Gerald Senarclens de Grancy

Concurrency

Definition

  • Ability of a program to be decomposed into parts that can run out of order or in partial order without affecting the final outcome
  • Composition of independently executing tasks
  • Concurrency is about managing multiple tasks, not speed
  • On a single CPU core, only one task executes at any given moment

Multiple tasks start, run, and complete in overlapping time periods

Time-slicing
On a single-core processor, the CPU switches back and forth between tasks so fast it seems like they are happening at the same time
graph LR
  T1[Task A
Part 1] --> T2[Task B
Part 1] T2 --> T3[Task A
Part 2] T3 --> T4[Task C
Part 1] T4 --> T5[Task B
Part 2] T5 --> | ... | T6[End] style T1 fill:#f9f style T2 fill:#ccf style T3 fill:#f9f style T4 fill:#ff9 style T5 fill:#ccf
Conceptual Timeline (Single Core)

Concurrency is a high-level concept

Parallelism

Definition

Independent sub-tasks run at the same time on multiple processing units

Think of processing units as CPU cores, GPU cores, or separate computers

Parallelism uses additional hardware to solve subproblems simultaneously

Multithreading

A way to achieve concurrency or parallelism using a single process

Threads may run in parallel if multiple cores are available

Example - Mobile Application

Task 1
Listening for touch inputs
Task 2
Fetching data from an API
Task 3
Updating a progress bar

If the tasks weren't structured concurrently,
the app would "freeze" while waiting for data

Race Condition

All threads within a process share the same memory space

This makes communication fast, but risky:
multiple threads might change the same variable "at once"

sequenceDiagram
    autonumber
    actor T1 as Thread 1
    participant Mem as Shared Memory
(counter = 10) actor T2 as Thread 2 Note over T1, T2: Goal: Both threads increment 'counter' %% --- The Intersection --- activate T1 Note right of T1: Step 1: READ Mem->>T1: Load counter (10) into Register A activate T2 Note left of T2: Step 2: READ (T2 runs before T1 writes) Mem->>T2: Load counter (10) into Register B Note left of T2: Step 3: INCREMENT Reg B = 11 Note left of T2: Step 4: WRITE T2->>Mem: Store Register B (11) Note right of T1: Step 5: INCREMENT Reg A = 11 %% --- The Collision --- Note right of T1: Step 6: WRITE (T1 overwrites T2's work) T1->>Mem: Store Register A (11) deactivate T1 deactivate T2 Note over T1, T2: Result: RACE CONDITION (Data Loss: counter = 11, expected: 12)

Multiprocessing

Multiprocessing is running tasks with isolated data

Each process has its own private memory space

Processes communicate via message passing

If one process crashes, the remaining processes can continue

Parallel computing can be used to improve performance (true parallelism)

Simultaneous task execution would require using two or more CPU cores

Mini-example: make -j8 compiles up to 8 source files in parallel

Example: Modern Web Browsers

Modern browsers like Firefox moved to a Multi-Process Architecture

  • The browser window and each individual tab are separate processes
  • If a tab's process crashes, other tabs and the main window stay alive
  • This also improves security (each tab has its own private memory space)

However, even though each tab uses its own process, each of those processes is still heavily multithreaded

Summary

Multithreading Multiprocessing
Execution one or more CPU cores one or more CPU cores
Memory shared separate
Applications responsive UIs CPU-heavy computations
Issues race conditions communication overhead
Paradigm concurrency + parallelism concurrency + parallelism

Use multithreading to "wait" for data (network responses, a database, ...)

Use multiprocessing for isolated tasks

Both multithreading and multiprocessing can be used for CPU heavy parallel computations (eg. video encoding)

Questions
and feedback...