Куда движется нить, когда будущее выходит за рамки? - PullRequest
6 голосов
/ 01 октября 2011

С потоками я знаю, что 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 s деструктор вызовет terminate(), когда он покидает область действия.

А как же future с?Куда идет нить?Это оторвано?Как это закончилось?

#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(), фьючерсы f1 и f2 уничтожаются.Но их темы все еще должны работать?Деструктор Fibrec называется, конечно. Но куда идут потоки? Программа не аварийно завершает работу, так что я думаю, что она присоединилась?Или может быть отстранен?Или они остановлены или отменены?Я считаю, что это не тривиально в C ++ 11?

Ответы [ 2 ]

12 голосов
/ 01 октября 2011

future - это результат асинхронной операции, он не является потоком сам по себе.Функция async порождает новый поток для выполнения вычислений, и когда он завершается, результат записывается в объект future.

В зависимости от реализованной политики вам придется либо вызвать .get() или .wait() на будущее, чтобы получить результат.Вызов этого будет выполнять работу в потоке , в котором он называется

Если policy равен std::launch::async, тогда INVOKE (fff, xyz ...) запускается в своем собственном потоке, Возвращенный std :: future станет готовым, когда этот поток завершится , и будет содержать либо возвращаемое значение, либо исключение, выданное вызовом функции. Деструктор последнего объекта будущего, связанный с асинхронным состоянием возвращенного std :: future, должен блокироваться, пока будущее не будет готово.

Если policy равен std::launch::deferred, то fff и xyz... хранятся в возвращенном std :: future как отложенный вызов функции.При первом вызове функций-членов wait () или get () в будущем, которое совместно использует одно и то же связанное состояние, синхронно выполняется INVOKE (fff, xyz ...) в потоке, который вызвал wait () или get ().

1 голос
/ 24 марта 2013

Вот очень базовая реализация 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...