A topic in the Open Knowledge Graph — a free, open map of 15,290 topics and the order to learn them in.

Semaphores

College Depth 104 in the knowledge graph ☐ I know this ☆ Set as goal
19topics build on this
411prerequisites beneath it
See this on the map →
Mutual Exclusion and LocksThread Scheduling and Coordination→→Barrier Synchronization PrimitivesCounting Semaphores and Resource Pools+4 more
semaphore binary-semaphore counting-semaphore P-V-operations Dijkstra

Core Idea

A semaphore, introduced by Dijkstra, is an integer synchronization variable with two atomic operations: wait (P) decrements the value and blocks if it becomes negative, and signal (V) increments the value and wakes a blocked thread if any. A binary semaphore (values 0 and 1) implements mutual exclusion and behaves like a mutex. A counting semaphore (any non-negative integer) tracks the count of available resources, enabling the classic producer-consumer and bounded-buffer patterns. Unlike mutexes, a semaphore can be signaled by a thread different from the one that waited, making them suitable for signaling between threads.

How It's Best Learned

Implement the bounded-buffer (producer-consumer) problem using two counting semaphores (empty slots, full slots) plus a mutex. Trace through an execution by hand, showing how the semaphore values change.

Common Misconceptions

Explainer

You already understand that mutexes provide mutual exclusion — only one thread enters the critical section at a time. A semaphore generalizes this idea by replacing the binary locked/unlocked state with an integer counter, enabling a much wider range of synchronization patterns. Dijkstra introduced semaphores in 1965, naming the two operations P (from the Dutch *proberen*, to test) and V (*verhogen*, to increment). In modern terminology these are called wait and signal, but the semantics are identical: wait decrements the counter and blocks if it goes negative; signal increments the counter and wakes a blocked thread if any are waiting.

A binary semaphore has values restricted to 0 and 1 and behaves like a mutex — wait locks it, signal unlocks it. The key difference is ownership: a mutex must be released by the same thread that acquired it, but a semaphore can be signaled by any thread. This makes semaphores ideal for signaling between threads. For example, a parent thread can wait on a semaphore initialized to 0; when the child thread finishes its setup, it signals the semaphore, and the parent unblocks. No mutex can express this pattern cleanly because no single thread "owns" both sides of the interaction.

A counting semaphore starts at some value N representing the number of available resources. Each wait decrements the count, and each signal increments it. When the count reaches zero, the next thread to wait blocks until another thread signals. This is the foundation of the bounded-buffer (producer-consumer) pattern: one counting semaphore tracks empty slots, another tracks full slots, and together they coordinate producers and consumers without busy-waiting.

The discipline required with semaphores is strict: every wait must have a matching signal, and the order matters. If you wait on two semaphores in different orders in different threads, you risk deadlock. If you forget a signal, a thread blocks forever. If you add an extra signal, a thread enters a critical section when it should not. Unlike higher-level constructs like monitors, semaphores give you no compile-time safety net — correctness depends entirely on the programmer placing P and V in the right places. This is both their power and their danger, which is why understanding them thoroughly is essential before moving on to monitors and condition variables.

Practice Questions 5 questions

Prerequisite Chain

Understanding Zero → The Number Zero → Counting to Five → Counting to 10 → Counting to 20 → Counting a Set of Objects Up to 20 → Cardinality: The Last Number Counted → Matching Numerals to Quantities → Subitizing Small Quantities → Addition Within 10 → Number Bonds to 10 → Addition Within 20 → Doubles and Near Doubles → Doubles Facts Within 10 → Near Doubles Facts Within 20 → Mental Math Strategies for Addition → Mental Math: Adding and Subtracting Tens → Addition Within 100 → Repeated Addition as Multiplication → Multiplication as Equal Groups → Multiplication: Arrays → Basic Multiplication Facts (0s, 1s, 2s, 5s, 10s) → Multiplication Facts Within 100 → Division as Equal Sharing → Division as Grouping (Measurement Division) → Division: Grouping (Repeated Subtraction) Model → Division: Fair Sharing Model → Division as Equal Sharing → Division as Grouping → Basic Division Facts → Division Facts Within 100 → Multiplication and Division Fact Families → Relationship Between Multiplication and Division → Division Facts as Inverse of Multiplication → Remainders and Quotients in Division → Division Word Problems → Multi-Step Word Problems → Solving Multi-Step Word Problems → Multiplication Word Problems → Division Word Problems → Introduction to Long Division → Factors and Multiples → Prime and Composite Numbers → Equivalent Fractions → Relating Fractions and Decimals → Decimal Place Value → Integers and the Number Line → Comparing and Ordering Integers → Absolute Value → Adding Integers → Subtracting Integers → Multiplying Integers → Introduction to Exponents → Order of Operations → Integer Order of Operations → Variable Expressions → The Distributive Property → Variables and Expressions Review → Introduction to Polynomials → Adding and Subtracting Polynomials → Multiplying Polynomials → Factorial → Permutations → Combinations → Counting Principles: Addition and Multiplication Rules → Introduction to Graph Theory → Propositional Logic Foundations → Logical Equivalences → Boolean Algebra → Boolean Type and Truth Values → Comparison Operators and Boolean Tests → Logical Operators and Boolean Algebra → Boolean Algebra and Fundamental Laws → Logic Gates Fundamentals → Implementing Boolean Functions with Gates → Karnaugh Map Simplification → Combinational Circuit Design → Flip-Flops and Latches → Binary Counters: Design and Analysis → Binary Arithmetic → Fixed-Point Number Representation → Two's Complement Representation → Overflow and Underflow Detection → Binary Adders: Half-Adders and Full-Adders → Full Adder and Carry Propagation → Carry Lookahead Adder Design → Half Adder Circuit Design → Multiplication Circuit Design → Sequential Circuit Design → Registers and Register Files → Instruction Set Architecture (ISA) → Kernel Architecture and OS Structure → System Calls and User/Kernel Mode → Processes and the Process Control Block → Process Creation: fork() and exec() → Process Termination and Resource Cleanup → Process States and State Transitions → Process Model Formalization → Context Switching and CPU Dispatch → CPU Scheduling Fundamentals → Round-Robin (RR) Scheduling → First-Come-First-Served (FCFS) Scheduling → Scheduling Fairness and Starvation Prevention → Thread Scheduling and Coordination → Semaphores

Longest path: 105 steps · 411 total prerequisite topics

Prerequisites (2)

Leads To (6)