c++ 11 continuaciones asíncronas o intento de semántica.then()
c++11 stdasync (2)
El código siguiente se basa en las ideas de Herb Sutter de una implementación de una continuación de tipo .then ().
template<typename Fut, typename Work>
auto then(Fut f, Work w)->std::future<decltype(w(f.get()))>
{ return std::async([=] { w(f.get()); }); }
Esto se usaría como auto next = then(f, [](int r) { go_and_use(r); });
o similar.
Esta es una buena idea, pero tal como está, no funcionará (los futuros solo se mueven y no se pueden copiar). Me gusta la idea, ya que es probable que aparezca en las próximas versiones de c ++ hasta donde puedo adivinar (aunque como .then () o incluso esperar).
Antes de compartir los futuros o similares, me pregunto qué pensaría la comunidad de desbordamiento de pila de esta implementación específicamente con mejoras y sugerencias (incluso futuros compartidos).
Gracias de antemano por cualquier sugerencia.
(Soy consciente de que esto es una solución hasta que existe un mecanismo basado en estándares, ya que costará un hilo (tal vez))).
Aquí está la solución, probada con g ++ 4.8 y clang ++ 3.2:
template<typename F, typename W>
auto then(F&& f, W w) -> std::future<decltype(w(f.get()))>
{
cout<<"In thread id = "<<std::this_thread::get_id()<<endl;
return std::async(std::launch::async, w, f.get());
}
void test_then()
{
std::future<int> result=std::async([]{ return 12;});
auto f = then(std::move(result), [](int r) {
cout<<"[after] thread id = "<<std::this_thread::get_id()<<endl;
cout<<"r = "<<r<<endl;
return r*r;
});
cout<<"Final result f = "<<f.get()<<endl;
}
Encuentro 3 problemas con la implementacion anterior:
- Solo funcionará si pasas
std::shared_future
comoFut
. - La continuación puede querer una oportunidad para manejar excepciones.
- No siempre se comportará como se espera, ya que si no especifica
std::launch::async
, podría diferirse, por lo tanto, la continuación no se invoca como cabría esperar.
He tratado de abordar estos:
template<typename F, typename W, typename R>
struct helper
{
F f;
W w;
helper(F f, W w)
: f(std::move(f))
, w(std::move(w))
{
}
helper(const helper& other)
: f(other.f)
, w(other.w)
{
}
helper(helper&& other)
: f(std::move(other.f))
, w(std::move(other.w))
{
}
helper& operator=(helper other)
{
f = std::move(other.f);
w = std::move(other.w);
return *this;
}
R operator()()
{
f.wait();
return w(std::move(f));
}
};
}
template<typename F, typename W>
auto then(F f, W w) -> std::future<decltype(w(F))>
{
return std::async(std::launch::async, detail::helper<F, W, decltype(w(f))>(std::move(f), std::move(w)));
}
Utilizado de esta manera:
std::future<int> f = foo();
auto f2 = then(std::move(f), [](std::future<int> f)
{
return f.get() * 2;
});