Is the popular volatile polled flag pattern broken?
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
The “volatile polled flag” pattern is not universally correct or universally broken. Its safety depends heavily on the language memory model. In C and C++, using volatile as a thread-synchronization mechanism is wrong for normal multithreaded communication. In languages like Java and C#, volatile has stronger visibility semantics, so a simple stop flag can work, although busy polling may still be a poor design.
Why People Use The Pattern
The pattern usually looks like this:
- one thread sets a flag,
- another thread loops until the flag changes,
- no heavyweight lock is used.
That sounds attractive because it is simple and cheap. The problem is that memory visibility and ordering rules are language-specific, and “volatile” does not mean the same thing everywhere.
In C And C++, volatile Is Not Thread Synchronization
In C++ this is wrong for ordinary inter-thread signaling:
volatile prevents certain compiler optimizations around direct accesses, but it does not provide the full cross-thread synchronization guarantees needed for normal shared-state communication. The correct tool is an atomic.
That gives defined inter-thread visibility semantics.
In Java And C#, The Story Is Different
In Java and C#, volatile has language-level memory visibility guarantees that make a simple polled stop flag much more reasonable.
This can work for a simple signal because writes to a volatile field become visible to other threads according to the language memory model.
So if someone asks whether the pattern is “broken,” the correct first response is: which language?
Even When It Works, Busy Polling Has Costs
A second issue is efficiency. A tight spin loop burns CPU.
Even in a language where the visibility semantics are correct, a busy-wait loop can be wasteful unless:
- the wait is expected to be extremely short,
- low-latency reaction is worth the CPU cost,
- the environment is carefully controlled.
Otherwise, condition variables, events, channels, or futures are usually better designs.
Visibility Is Not The Same As Full Synchronization
Another subtle point is that a volatile flag may make the flag change visible without making a broader compound protocol safe.
For example, “flag is true, therefore all associated shared state is now safely published” may or may not be valid depending on the language semantics and the rest of the code. That is why atomics, mutexes, or higher-level synchronization often remain necessary when more than a single boolean signal is involved.
Better Alternatives Depend On The Use Case
For C and C++, use atomics for simple flags and mutexes or condition variables for richer coordination.
For Java and C#, a volatile stop flag can be acceptable for simple visibility, but higher-level coordination tools such as:
- '
waitandnotify,' - latches,
- semaphores,
- executors,
- cancellation tokens or similar abstractions,
are often easier to reason about in real systems.
A Better Question To Ask
Instead of asking “is the volatile polled flag pattern broken,” ask:
- what language memory model applies,
- is the flag only a simple stop signal,
- is busy spinning acceptable,
- does more shared state need coordinated publication.
Those questions determine whether the pattern is correct, inefficient, or both.
Common Pitfalls
- Assuming
volatilemeans thread-safe communication in every language. - Using C or C++
volatilewhere an atomic is required. - Treating a visible flag change as proof that all related shared state is safely synchronized.
- Ignoring the CPU cost of busy waiting.
- Asking language-independent concurrency questions when the semantics are language-defined.
Summary
- The volatile polled flag pattern is language-dependent.
- In C and C++,
volatileis not the right tool for ordinary thread signaling; use atomics. - In Java and C#, a simple volatile stop flag can work for visibility.
- Even when correct, busy polling may waste CPU and be a poor design choice.
- Judge the pattern by memory-model guarantees and coordination needs, not by folklore.
Related reading
- Is there a better waiting pattern for c?
- Is there a better way to create asynchronous updates without using setInterval?
- is there a 'block until condition becomes true' function in java?
- Is there a concurrent List in Java's JDK?
- Is there a data structure in C like a ConcurrentQueue which allows me to await an empty queue until an item is added?
- Is there a framework for simple, asynchronous, HTTP integration I/O?
- Is there a good way to Promise.all an array of objects which has a property as promise?
- Is there a right way to implement distributed caching (resistent to concurrent writing, netsplits, etc)?
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.