当future离开作用域时,线程要去哪里?

Where is the thread going when a future leaves scope?

本文关键字:线程 future 离开 作用域      更新时间:2023-10-16

对于线程,我知道terminate()在线程变量离开作用域时被调用:

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的析构函数将在terminate()离开作用域时调用它。

那么future s呢?他们运行的线程在哪里?它是分离的吗?它是如何结束的?

#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;
}

execit()不存在时,f1f2的期货将被销毁。但是他们的线程应该还在运行吗?当然,会调用Fibrec的析构函数。但是线程去哪里了?程序没有崩溃,所以我猜,这变成了连接?或者可能是超然的?或者它们被停止或取消了?我相信这在c++ 11中不是很容易做到的吧?

future是异步操作的结果,它本身不是一个线程。async函数生成一个新线程来进行计算,当计算完成后,结果被写入future对象。

根据实现的策略,您将不得不在将来调用.get().wait()来获得结果。调用该方法将在线程上完成该工作,该线程在

上调用该方法。

如果策略为std::launch::async,则在其上运行INVOKE(fff,xyz…)自己的线程。返回的std::future将在执行以下操作时准备好线程已完成,并且将保存返回值或异常由函数调用抛出。最后一个未来的析构函数对象的异步状态关联Std::future将阻塞,直到future准备好。

如果策略是std::launch::deferred,那么fff和xyz…存储在作为延迟函数调用返回的std::future中。第一个在共享的future上调用wait()或get()成员函数相同的关联状态将执行INVOKE(fff,xyz…)在调用wait()或get()的线程上同步执行。

这是一个非常基本的std::async实现(没有任务池或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;   
}

你可以看到实际的计算是在一个分离的线程中完成的。未来只是一个同步对象。std::packaged_task只是std::promise set_value/set_exception逻辑的另一个包装。