99 Advanced The Hundred
The async That Never Started
the worker that clocks in only when you look
using namespace std::chrono_literals;
std::atomic<int> checked{0};
int scan_files() {
std::cout << "scanner on thread " << std::this_thread::get_id() << "\n";
for (int i = 0; i < 4; ++i, ++checked)
std::this_thread::sleep_for(50ms);
return checked;
}
int main() {
std::cout << "main on thread " << std::this_thread::get_id() << "\n";
auto f = std::async(std::launch::deferred, scan_files); // scan in the background
std::this_thread::sleep_for(300ms);
std::cout << "300 ms later: checked = " << checked << "\n";
int total = f.get();
std::cout << "after f.get(): checked = " << total << "\n";
}
Run it. After 300 ms of background scanning, how many files are checked?
Answer
Zero — the scan hasn't begun. It starts inside f.get(), on main's own thread.
Typical output (GCC 11.5 on x86-64 Linux):
Why¶
std::launch::deferred means what it says: the callable is boxed up, nothing starts, and
the first get() or wait() runs it synchronously on the calling thread — hence the
two identical ids. Never touch the future and the function is never invoked at all, unlike
entry 100, where a real async future's destructor blocks until the task finishes. The
trap is the default: plain std::async(f) means std::launch::async |
std::launch::deferred, and the implementation picks — a conforming library may defer every
time. Delete std::launch::deferred, and GCC 11.5's libstdc++ does start a real thread
here (different id, checked = 4 at 300 ms), but that is a vendor's habit, not a promise,
and nothing in -Wall -Wextra warns about any of it.
The fix¶
Say what you mean — std::launch::async must start a thread or throw std::system_error:
auto f = std::async(std::launch::async, scan_files); // really concurrent
if (f.wait_for(0s) == std::future_status::deferred) { /* ... */ } // catch one in the act
Takeaway: with no launch policy, concurrency is optional — spell out
std::launch::async, or you may have written a very ornate function call.
Try it: g++ -std=c++17 -pthread main.cpp -o demo && ./demo