In a tutorial I am following, the author wrote a program that showed that the destructors of std::future
s don't always execute the task. In the following program, 10 threads created with std::async()
are moved into the vector, and then we wait for their destructors to run.
#include <iostream>
#include <future>
#include <thread>
#include <chrono>
int main()
{
std::cout << "Main thread id: " << std::this_thread::get_id() << std::endl;
std::vector<std::future<void>> futures;
for (int i = 0; i < 10; ++i)
{
auto fut = std::async([i]
{
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << std::this_thread::get_id() << " ";
});
futures.push_back(std::move(fut));
}
}
The result is machine-dependent, but what we found was that only 6 threads were launched when the destructors ran (we only got 6 ids printed after the main thread id output). This meant that the other four were deferred, and deferred threads don't run during std::future
's destructors.
My question is why were some threads forced to execute while others were deferred. What is the point of deferring them if the life of the std::future
is ending?
the author wrote a program that showed that the destructors of std::futures don't always execute the task.
The destructors never execute the task. If the task is already executing in another thread the destructor waits for it to finish, but it does not execute it.
what we found was that only 6 threads were launched when the destructors ran
This is incorrect, the threads are not launched when the destructors run, they are launched when you call std::async
(or some time after that) and they are still running when the destructors start, so the destructors must wait for them.
What is the point of deferring them if the life of the std::future is ending?
Again, they are not deferred when the destructor runs, they are deferred when std::async
is called, they are still deferred when the destructor runs, and so they just get thrown away without being run, and the destructor doesn't have to wait for anything.
I don't know if you're quoting the tutorial and the author of that is confused, or if you're confused, but your description of what happens is misleading.
Each time you call std::async
without a launch policy argument the C++ runtime decides whether to create a new thread or whether to defer the function (so it can be run later). If the system is busy the runtime might decide to defer the function because launching another thread would make the system even slower.
Your async()
calls use the default launch policy, which is launch::async|launch::deferred
meaning that "The function chooses the policy automatically (at some point). This depends on the system and library implementation, which generally optimizes for the current availability of concurrency in the system."
thread::hardware_concurrency
may give you hints about maximum hardware concurrency on your system. This can contribute to explain why some threads are necessarily deferred (especially if your loop is grater than the hardware concurrency) or not. However, beware that other running processes might use the hardware concurrency as well.
Please note as well that your asynchronous threads make use of cout
which could delay some of them due to synchronization (more here)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With