Where does the thread go when the future leaves its appearance?

In threads, I know that terminate() is called when a thread variable leaves scope:

 size_t fibrec(size_t n) { return n<2 ? 1 : fibrec(n-2)+fibrec(n-1); } int main() { std::thread th{ fibrec, 35 }; // no join here } // ~th will call terminate(). 

th destructor will call terminate() when it leaves scope.

But what about future s? Where is the thread they start? Did he separate? How did it end?

 #include <iostream> #include <future> // async using namespace std; size_t fibrec(size_t n) { return n<2 ? 1 : fibrec(n-2)+fibrec(n-1); } struct Fibrec { size_t operator()(size_t n) { return fibrec(n); } const size_t name_; Fibrec(size_t name) : name_(name) {} ~Fibrec() { cerr << "~"<<name_<< endl; } }; void execit() { auto f1 = async( Fibrec{33}, 33 ); auto f2 = async( Fibrec{34}, 34 ); // no fx.get() here !!! }; // ~f1, ~f2, but no terminate()! Where do the threads go? int main() { auto f0 = async( Fibrec{35}, 35 ); execit(); cerr << "fib(35)= " << f0.get() << endl; } 

When execit() left, the futures f1 and f2 will be destroyed. But should their threads still work? Of course, the Fibrec destructor is called. But where are the flows going? The program does not crash, so I suppose it becomes integrated? Or maybe separated? Or are they discontinued or canceled? I believe this is not trivially done in C ++ 11?

+6
source share
2 answers

future is the result of the async operation; it is not a stream in itself. The async function generates a new thread for performing calculations, and when this is completed, the result is written to the future object.

Depending on the policy implemented, you will have to either call .get() or .wait() in the future to get the result. Calling this will do the work on the thread it is called on.

If the policy is std::launch::async , then the INVOKE function (fff, xyz ...) is executed on its own thread. The returned std :: future will be ready when this thread is completed and will contain either the return value or the exception thrown by the function call. The destructor of the last future object associated with the asynchronous state of the returned std :: future is blocked until the future is ready.

If the policy is std::launch::deferred , then fff and xyz ... are saved in the future returned by std :: as a deferred function call. The first call to the wait () or get () functions in the future that share the same bound state will execute INVOKE (fff, xyz ...) synchronously in the thread that calls wait () or get ().

+12
source

Here is a very simple implementation of std::async (without a task pool or std::launch ):

 template< class Function, class... Args> std::future<typename std::result_of<Function(Args...)>::type> async( Function&& f, Args&&... args ) { std::packged_task<F(Args...)> task(std::forward<F>(f), std::forward<Args>(args)...); auto ret = task.get_future(); std::thread t(std::move(task)); t.detach(); return ret; } 

You see that the actual calculation is done in a separate thread. The future is just an object of synchronization. std::packaged_task is another shell for the std::promise set_value / set_exception .

+1
source

Source: https://habr.com/ru/post/898444/


All Articles