Obtener el estado de un std :: future

82

¿Es posible comprobar si std::futureha finalizado o no? Por lo que puedo decir, la única forma de hacerlo sería llamar wait_forcon una duración cero y verificar si el estado es readyo no, pero ¿hay una mejor manera?

David Brown
fuente
10
@CatPlusPlus A menos que me equivoque, validsolo comprueba si el futuro tiene un estado compartido (es decir, vuelve truehasta que getse llame al futuro).
David Brown
Entonces, si getha sido llamado y devuelve el valor almacenado, ¿aún lo desea true? (No estoy seguro de por qué esto sería útil, ya que solo puede obtener el valor una vez).
James McNellis
@JamesMcNellis quizás estoy malinterpretando o haciendo un mal uso de los futuros, pero lo que quiero es saber si el hilo (o lo que sea que esté realizando el cálculo) está terminado o no. QFuture::isFinishedBásicamente, el equivalente de Qt .
David Brown
1
Una espera con un tiempo de espera cero es la forma en que la mayoría de las API en muchas plataformas tratan este concepto ... Tanto es así que lo consideraría la forma "estándar" de abordar el concepto. Esto me deja un poco perplejo ante la noción de "una mejor manera" ...
asveikau
16
@asveikau No sabía que esta era una práctica estándar. Simplemente se siente extraño llamar a una función de espera cuando no deseo esperar.
David Brown

Respuestas:

84

Tiene razón, y aparte de llamar wait_untilcon un tiempo en el pasado (que es equivalente) no hay mejor manera.

Siempre puede escribir una pequeña envoltura si desea una sintaxis más conveniente:

template<typename R>
  bool is_ready(std::future<R> const& f)
  { return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready; }

Nota: si la función se aplaza, esto nunca volverá a ser verdadero, por lo que probablemente sea mejor verificar wait_fordirectamente en el caso de que desee ejecutar la tarea aplazada de forma sincrónica después de que haya pasado un cierto tiempo o cuando la carga del sistema sea baja.

Jonathan Wakely
fuente
2
wait_for no muta el futuro, por lo que el parámetro podría declararse como const.
Jens Åkerblom
7
Considere marcar valid () primero para evitar errores de tiempo de ejecución si ya se llamó a get o si el futuro nunca se inicializó.
Jeremy Sorensen
5
¿Se garantiza que wait_for (chrono :: seconds (0)) regresará inmediatamente o podría ceder el control del hilo durante un par de milisegundos en algunas implementaciones? Esto sería muy importante saber como un par de milisegundos es mucho tiempo al codificar un juego ...
kynnysmatto
9
@kynnysmatto, en algunas implementaciones adquiere un bloqueo mutex para inspeccionar de forma segura el estado del futuro, por lo que si ese bloqueo se resuelve (porque otro hilo está preparando el estado, o también verificando que esté listo), entonces se bloqueará, y otro hilo podría ejecutarse, pero en una buena implementación, el mutex nunca debe mantenerse durante más de unas pocas instrucciones, por lo que ni siquiera un milisegundo. La implementación actual de GCC no usa un mutex en absoluto, pero la anterior sí lo hizo y hacer que el estado esté listo se realiza intercambiando dos punteros, por lo que el mutex solo se bloquea muy brevemente mientras eso sucede.
Jonathan Wakely
@JonathanWakely probar con g ++ for(int i = 0; i < 1000; i++) f.wait_for(chrono::seconds(0));toma 43 ms de tiempo de reloj de pared.
Daniel Kinsman
14

Hay una función miembro is_ready en proceso para std :: future. Mientras tanto, la implementación de VC tiene un miembro _Is_ready ().

Rick Yorgason
fuente
Tenga en cuenta que la función miembro _Is_ready () NO es segura para subprocesos. Accede a la bandera _Ready del estado asociado de forma desprotegida. Este es al menos el caso de VS2019 16.2.
Mattias De Charleroy
9

Mi primera apuesta sería igualar wait_forcon una duración de 0 y verificar el código de resultado que puede ser uno de future_status::ready, future_status::deferredo future_status::timeout.

En cppreference afirman que valid() verifica si el resultado está disponible , pero el estándar dice que valid()regresará truesi se *thisrefiere a un estado compartido, independientemente de si ese estado está listo o no.

David Rodríguez - dribeas
fuente
7
cppreference ahora se ha actualizado y establece "comprueba si el futuro tiene un estado compartido". (No estoy seguro si desea eliminar su segundo párrafo o editarlo, así que no lo modificaré yo mismo).
Predeterminado el