c++ concurrency c++17 stdasync std-future

c++ - comportamiento de std:: async(std:: launch:: aplazado)+std:: future:: then



concurrency c++17 (1)

Esto, en mi opinión, parece ser un error en el TS . O al menos una trampa poco documentada.

Aquí está el texto del TS:

2.3 [futures.unique_future] / 6-10

template <class F> see below then(F&& func);

Requiere:

INVOKE(DECAY_COPY (std::forward<F>(func)), std::move(*this)) shall be a valid expression.

Efectos:

La función crea un estado compartido que está asociado con el objeto futuro devuelto. Adicionalmente,

Cuando el estado compartido del objeto está listo, se INVOKE(DECAY_COPY(std::forward<F>(func)), std::move(*this)) la continuación INVOKE(DECAY_COPY(std::forward<F>(func)), std::move(*this)) en un subproceso de ejecución no especificado con la llamada a DECAY_COPY() siendo evaluado en el hilo que llamaba entonces.

Cualquier valor devuelto de la continuación se almacena como resultado en el estado compartido del futuro resultante. Cualquier excepción propagada por la ejecución de la continuación se almacena como el resultado excepcional en el estado compartido del futuro resultante.

Devoluciones:

Cuando result_of_t<decay_t<F>(future<R>)> es future<R2> , para algún tipo de R2, la función devuelve future<R2> . De lo contrario, la función devuelve future<result_of_t<decay_t<F>(future<R>)>> . [Nota: la regla anterior se denomina desenvolvimiento implícito. Sin esta regla, el tipo de retorno de tomar un retornable future<R> habría sido future<future<R>> . Esta regla evita tales objetos futuros anidados. El tipo de f2 continuación es el future<int> y no el future<future<int>> :

[Ejemplo:

future<int> f1 = g(); future<int> f2 = f1.then([](future<int> f) { future<int> f3 = h(); return f3; });

- ejemplo final]

- nota final]

Postcondiciones:

valid() == false en el futuro original. valid() == true en el futuro devuelto desde entonces. [Nota: En el caso de que se haya desempaquetado implícito, la validez del futuro devuelto desde thenfunc no se puede establecer hasta después de la finalización de la continuación. Si no es válido, el futuro resultante estará listo con una excepción de tipo std::future_error , con una condición de error de std::future_errc::broken_promise . - nota final]

No hay ningún caso especial para una tarea futura diferida. Si esa tarea futura diferida no está lista antes de llamar a .then , no hay forma de que esté lista, por lo que no hay forma de invocar la copia descompuesta de la func .

El texto para shared_future es similar; allí, sin embargo, puede hacer que el shared_future esté listo después de llamar .then .

Si se pretende esto; que, .then en un futuro único diferido no listo, resultará en un valor de retorno de un future que nunca se puede preparar, esto debería estar explícito en la norma TS /. Si esto no se pretende, el texto estándar debe ser cambiado.

Tenga en cuenta que estos cambios no aparecen en el borrador de norma N4762 publicado en 2018.

No estoy seguro de cómo el estándar debería arreglar esto; la semántica es razonable para un shared_future pero no para un future , y una semántica diferente sería sorprendente.

La idea detrás de un futuro diferido (que solo se logra llamando a std::async con std::launch::deferred flag) es que la devolución de llamada se realiza solo cuando alguien intenta esperar o extraer el valor futurista o la excepción del futuro. para entonces la devolución de llamada no se ejecuta.

¿Qué sucede si adjunto una continuación a un futuro diferido con std::future::then ? el futuro diferido se pierde (y then invalida el futuro) y en su lugar se devuelve un nuevo futuro.

En este caso, según la norma, ¿qué debería pasar? ¿El nuevo futuro es también un futuro diferido? ¿Sería un punto muerto? Esta pregunta no se aborda en la documentación más reciente.