std::condition_variable_any::wait_until
template<class Lock, class Clock, class Duration > std::cv_status | (1) | (desde C++11) |
template<class Lock, class Clock, class Duration, class Pred > bool wait_until( Lock& lock, | (2) | (desde C++11) |
template<class Lock, class Clock, class Duration, class Pred > bool wait_until( Lock& lock, | (3) | (desde C++20) |
wait_until
hace que el hilo actual se bloquee hasta que se notifique a la variable de condición o se produzca un despertar espurio, opcionalmente en bucle hasta que se satisfaga algún predicado.
lock
, bloquea el hilo en ejecución actual y lo agrega a la lista de hilos en espera de *this. El hilo se desbloqueará cuando se ejecute notify_all() o notify_one(), o cuando se alcance el punto de tiempo absoluto timeout_time
. También se puede desbloquear de forma espuria. Cuando se desbloquea, independientemente del motivo, se vuelve a tomar posesión de lock
y wait_until
sale.while(!pred()){if(wait_until(lock, timeout_time)==std::cv_status::timeout){return pred();}}returntrue;
condition_variable_any
por la duración de wait_until(), a ser notificado si se hace una solicitud de entonces es equivalente a while(!stoken.stop_requested()){if(pred())returntrue;if(wait_until(lock, timeout_time)==std::cv_status::timeout)return pred();}return pred();
Si estas funciones no cumplen con la poscondición (lock se bloquea por el hilo llamante), se llama a std::terminate. Por ejemplo, esto podría suceder si al volver a bloquear el mutex se lanza una excepción.
Clock
debe cumplir con los requerimientos de Clock. El programa está mal formado si std::chrono::is_clock_v<Clock> es false.(desde C++20)
Contenido |
[editar]Parámetros
lock | - | Un objeto de tipo Lock que cumple con los requerimientos de BasicLockable, que debe estar bloqueado por el hilo actual. |
stoken | - | Un símbolo de detención std::stop_token para el cual registrar la interrupción. |
timeout_time | - | Un objeto de tipo std::chrono::time_point que representa el momento en que dejar de esperar. |
pred | - | Predicado que devuelve false si la espera debería continuar.. La signatura de la función predicado deberá ser equivalente a lo siguiente: bool pred(); |
[editar]Valor de retorno
timeout_time
se alcanzó, std::cv_status::no_timeout de lo contrario.pred
todavía se evalúa a false después de que el tiempo de espera timeout_time
expiró, true de lo contrario. Si el tiempo de espera ya expiró, se evalúa y devuelve el resultado de pred
.[editar]Excepciones
pred
.[editar]Notas
El estándar recomienda que se utilice el reloj vinculado a timeout_time
para medir el tiempo; ese reloj no tiene por qué ser un reloj monótono. No hay garantías con respecto al comportamiento de esta función si el reloj se ajusta de manera discontinua, pero las implementaciones existentes convierten timeout_time
de Clock
a {{lc|std::chrono::system_clock} } y delegan a POSIX pthread_cond_timedwait
para que la espera respete los ajustes del reloj del sistema, pero no los del Clock
proporcionado por el usuario. En cualquier caso, la función también puede esperar más tiempo que hasta después de que se haya alcanzado timeout_time
debido a demoras en la programación o en la contención de recursos.
Incluso si el reloj en uso es std::chrono::steady_clock u otro reloj monótono, un ajuste del reloj del sistema puede inducir un despertar espurio.
Los efectos de notify_one()
/notify_all()
y cada una de las tres partes atómicas de wait()
/wait_for()
/wait_until()
(desbloquear+esperar, despertar y bloquear) tienen lugar en un solo orden total que se puede ver como el orden de modificación de una variable atómica: el orden es específico para esta variable de condición individual. Esto hace imposible que notify_one()
por ejemplo, se retrase y desbloquee un hilo que comenzó a esperar justo después de que se hizo la llamada a notify_one()
.
[editar]Ejemplo
#include <iostream>#include <atomic>#include <condition_variable>#include <thread>#include <chrono>usingnamespace std::chrono_literals; std::condition_variable cv;std::mutex cv_m;std::atomic<int> i{0}; void espera(int idx){std::unique_lock<std::mutex> lk(cv_m);auto now =std::chrono::system_clock::now();if(cv.wait_until(lk, now + idx*100ms, [](){return i ==1;}))std::cerr<<"Hilo "<< idx <<" ha terminado la espera. i == "<< i <<'\n';elsestd::cerr<<"Hilo "<< idx <<" agotado. i == "<< i <<'\n';} void indica(){std::this_thread::sleep_for(120ms);std::cerr<<"Notificando...\n"; cv.notify_all();std::this_thread::sleep_for(100ms); i =1;std::cerr<<"Notificando de nuevo...\n"; cv.notify_all();} int main(){std::thread t1(espera, 1), t2(espera, 2), t3(espera, 3), t4(indica); t1.join(); t2.join(); t3.join(); t4.join();}
Posible salida:
Hilo 1 agotado. i == 0 Notificando... Hilo 2 agotado. i == 0 Notificando de nuevo... Hilo 3 ha terminado la espera. i == 1
[editar]Informes de defectos
Los siguientes informes de defectos de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.
ID | Aplicado a | Comportamiento según lo publicado | Comportamiento correcto |
---|---|---|---|
LWG 2093 | C++11 | Faltaban excepciones relacionadas con el tiempo de espera en la especificación. | Se mencionan. |
LWG 2135 | C++11 | wait_until lanzaba una excepción cuando fallaba el desbloqueo y rebloqueo. | Llama a std::terminate. |
[editar]Véase también
[editar]See also
Bloquea el hilo actual hasta que la variable de condición se despierte. (función miembro pública) | |
Bloquea el hilo actual hasta que la variable de condición se despierte o hasta después del tiempo de espera especificado. (función miembro pública) | |
Documentación de C para cnd_timedwait |