What Limitation of stdasync is Stroustrup Referring To?
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
When Stroustrup points out limitations of std::async, he is usually referring to the fact that it gives you too little control over how work is scheduled and executed. The biggest practical issue is that the default launch policy allows the implementation to choose between real asynchronous execution and deferred execution. That makes behavior less predictable than many developers expect, and it also exposes the broader design limitation that std::async is not a full executor or thread-pool abstraction.
The Default Policy Is Ambiguous
If you call std::async without an explicit launch policy, the implementation may choose either:
- '
std::launch::async,' - '
std::launch::deferred,' - or a combination policy.
This looks like it “obviously” launches a new asynchronous task, but the standard allows the implementation to defer execution until get() or wait() is called.
That ambiguity is the first major limitation.
Why That Matters
If execution may be deferred, then code that looks concurrent may actually run synchronously at the point of get(). That affects:
- performance expectations,
- latency behavior,
- scalability reasoning,
- portability across implementations.
A developer may think they are scheduling parallel work, while the implementation is really just postponing the function call.
You Can Force A Policy, But That Only Solves Part Of The Problem
You can remove that particular ambiguity by writing:
or:
That helps, but it does not solve the deeper limitation: std::async still does not let you choose an executor, thread pool, queueing policy, or scheduling strategy.
The Bigger Limitation: No Execution Model Control
Modern concurrency design often wants more than “run this eventually.” It wants explicit control over:
- which pool runs the work,
- how many worker threads exist,
- what happens under load,
- how tasks are composed,
- how cancellation or prioritization is handled.
std::async does not provide that. It is a convenience API, not a complete scheduling framework.
This is one reason many serious systems end up using:
- explicit thread pools,
- task schedulers,
- executors,
- library-specific concurrency frameworks.
Future Semantics Add More Surprise
Another source of discomfort is the interaction between futures and waiting behavior. In some situations, developers discover that simply holding or destroying a future can affect when synchronization happens, which is more subtle than “fire-and-forget task launch.”
That makes std::async convenient for small examples but less satisfying as a foundation for large, predictable concurrency architectures.
What std::async Is Good At
It is still useful when you want a small, simple future-producing task with minimal code.
For simple task-based code, that is elegant. The limitation is not that std::async is useless. The limitation is that it is less controllable and less expressive than a serious execution framework.
A Better Mental Model
Think of std::async as a convenience wrapper for launching work with a future result, not as the final answer to structured concurrency or scalable scheduling.
That framing makes Stroustrup’s criticism easier to understand. The complaint is not “this feature never works.” It is “this feature does not give enough control or predictability for broader concurrency design.”
Common Pitfalls
- Assuming
std::asyncwithout a policy always creates a new thread immediately. - Treating deferred execution as if it were true background parallelism.
- Using
std::asyncwhere a thread pool or executor model is really needed. - Building large concurrency designs around a convenience API that provides little scheduling control.
- Missing that implementation freedom can create portability differences in observed behavior.
Summary
- The main limitation of
std::asyncis lack of control and predictability in task scheduling. - The default launch policy may choose deferred execution instead of real async execution.
- Explicit launch policies help, but they do not turn
std::asyncinto an executor framework. - '
std::asyncis useful for simple future-based tasks, not as a complete concurrency architecture.' - Stroustrup’s criticism is mainly about execution-model limitations, not about basic usability.
Related reading
- What operations are atomic in C?
- What operations in Java are considered atomic?
- What q.defer really does?
- What resources are shared between threads?
- What should main() return in C and C++?
- What STL algorithm can determine if exactly one item in a container satisfies a predicate?
- What server-side architectures could provide high availability and avoid race conditions?
- What should I decorate with asyncio.coroutine for async operations?
.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.