Thread Scheduling and Coordination

College Depth 70 in the knowledge graph I know this Set as goal
Unlocks 1 downstream topic
threads scheduling coordination

Core Idea

Threads share a process's address space but maintain independent execution stacks and program counters. Independent scheduling of threads requires explicit synchronization mechanisms to coordinate shared data access and prevent race conditions.

How It's Best Learned

Implement simple concurrent programs with race conditions, observe the failures, then add locks to fix them.

Common Misconceptions

Explainer

You know from studying threads that multiple threads within a process share the same address space — the same heap, the same global variables, the same code. And from the process model, you know that each execution context has its own program counter and stack. When the OS scheduler decides to run a different thread, it performs a context switch that saves one thread's registers and restores another's. The critical insight is that these switches can happen at any point — between any two machine instructions — and this unpredictability is what makes concurrent programming fundamentally different from sequential programming.

Consider a simple example: two threads both increment a shared counter. The operation `counter += 1` looks atomic in source code, but at the machine level it decomposes into three steps: load the value from memory into a register, add one, and store the result back. If thread A loads the value (say, 5), then gets preempted before storing, thread B loads the same value 5, increments to 6, and stores it. When thread A resumes, it stores its result — also 6. Two increments happened, but the counter only went up by one. This is a race condition: the result depends on the unpredictable timing of thread scheduling.

Race conditions are not bugs in the scheduler — they are bugs in the program. The scheduler is doing exactly what it should: sharing the CPU among threads. The problem is that the program accesses shared data without synchronization. The simplest synchronization primitive is a lock (or mutex): a thread acquires the lock before accessing shared data and releases it afterward. While the lock is held, any other thread that tries to acquire it will block until the first thread releases it. This guarantees that the load-increment-store sequence completes without interruption, making the operation effectively atomic from the perspective of other threads.

But synchronization introduces its own challenges. Locks create contention — threads waiting for locks are doing no useful work, reducing parallelism. Using too few locks risks race conditions; using too many risks deadlock, where two threads each hold a lock the other needs. Beyond locks, threads need ways to coordinate their execution order — for example, a producer thread must signal a consumer thread that data is ready. These coordination patterns lead to higher-level primitives like condition variables and semaphores, which you will study next. The fundamental lesson here is that shared memory is not free communication — it is a shared resource that requires disciplined access protocols, just like any other shared resource in an operating system.

Practice Questions 5 questions

Prerequisite Chain

Counting to 10Counting to 20Understanding ZeroThe Number ZeroCounting to FiveOne-to-One CorrespondenceCombining Small Groups Within 5Addition Within 10Addition Within 20Two-Digit Addition Without RegroupingTwo-Digit Addition with RegroupingAddition Within 100Repeated Addition as MultiplicationMultiplication Facts Within 100Division as Equal SharingDivision as Grouping (Measurement Division)Division: Grouping (Repeated Subtraction) ModelDivision: Fair Sharing ModelDivision as Equal SharingDivision as GroupingBasic Division FactsDivision Facts Within 100Two-Digit by One-Digit DivisionDivision with RemaindersRemainders and Quotients in DivisionDivision Word ProblemsIntroduction to Long DivisionFactors and MultiplesPrime and Composite NumbersEquivalent FractionsRelating Fractions and DecimalsDecimal Place ValueReading and Writing DecimalsComparing and Ordering DecimalsAdding and Subtracting DecimalsMultiplying DecimalsDividing DecimalsDividing FractionsMixed Number ArithmeticOrder of OperationsOperators and ExpressionsArithmetic Operators and Operator PrecedenceComparison Operators and Boolean TestsLogical Operators and Boolean AlgebraBoolean Algebra and Fundamental LawsCombinational Circuit DesignFlip-Flops and LatchesBinary Counters: Design and AnalysisBinary ArithmeticFixed-Point Number RepresentationTwo's Complement RepresentationOverflow and Underflow DetectionBinary Adders: Half-Adders and Full-AddersFull Adder and Carry PropagationCarry Lookahead Adder DesignHalf Adder Circuit DesignMultiplication Circuit DesignSequential Circuit DesignRegisters and Register FilesInstruction Set Architecture (ISA)Kernel Architecture and OS StructureSystem Calls and User/Kernel ModeProcesses and the Process Control BlockProcess Creation: fork() and exec()Process Termination and Resource CleanupProcess States and State TransitionsThreads and ConcurrencyThe Critical Section Problem and Race ConditionsMutual Exclusion and LocksPriority Scheduling and Priority InversionThread Scheduling and Coordination

Longest path: 71 steps · 266 total prerequisite topics

Prerequisites (4)

Leads To (1)