std::condition_variable
Definido en el archivo de encabezado <condition_variable> | ||
class condition_variable; | (desde C++11) | |
La clase condition_variable
es una primitiva de sincronización que se puede usar para bloquear un hilo, o varios hilos al mismo tiempo, hasta que otro hilo modifique una variable compartida (la condición) y notifique a la variable de condición, condition_variable
.
El hilo que pretende modificar la variable compartida debe:
- tomar posesión de un
std::mutex
(típicamente mediante std::lock_guard); - realizar la modificación mientras se mantiene el bloqueo;
- ejecutar notify_one o notify_all en la variable de condición,
std::condition_variable
(no necesita mantenerse el bloqueo para la notificación).
Incluso si la variable compartida es atómica, debe modificarse bajo el mutex para publicar correctamente la modificación en el hilo en espera.
Cualquier hilo que tiene la intención de esperar en std::condition_variable
debe:
- tomar posesión de un std::unique_lock<std::mutex>, en el mismo mutex que se usó para proteger la variable compartida;
- ya sea:
- verificar la condición, en caso de que ya haya sido actualizada y notificada;
- ejecutar wait, wait_for, o wait_until. Las operaciones de espera liberan atómicamente el mutex y suspenden la ejecución del hilo.
- cuando se notifica a la variable de condición, expira un tiempo de espera o se produce un despertar espurio o falso el hilo se despierta y se vuelve a tomar posesión del mutex atómicamente; luego el hilo debe verificar la condición y continuar esperando si el despertar fue falso.
- o:
- usar la sobrecarga que toma un predicado (parámetro de plantilla
Predicate
) de wait, wait_for, y wait_until, que se encarga de los tres pasos anteriores.
std::condition_variable
solamente funciona con std::unique_lock<std::mutex>; esta restricción permite la máxima eficiencia en algunas plataformas. std::condition_variable_any proporciona una variable de condición que funciona con cualquier objeto BasicLockable, como std::shared_lock.
Las variables de condición permiten la invocación simultánea de las funciones miembro wait, wait_for, wait_until, notify_one y notify_all.
La clase std::condition_variable
cumple con los requerimientos de StandardLayoutType. No es CopyConstructible, MoveConstructible, CopyAssignable, o MoveAssignable.
Contenido |
[editar]Tipos miembro
Tipo miembro | Definición |
native_handle_type | definido por la implementación |
[editar]Funciones miembro
Construye el objeto. (función miembro pública) | |
Destruye el objeto. (función miembro pública) | |
operator= [eliminada] | No es asignable mediante copia. (función miembro pública) |
Notificación | |
Notifica a un hilo en espera. (función miembro pública) | |
Notifica a todos los hilos en espera. (función miembro pública) | |
Espera | |
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) | |
Bloquea el hilo actual hasta que la variable de condición se despierte o se haya alcanzado el punto de tiempo especificado. (función miembro pública) | |
Identificador nativo | |
Devuelve el identificador nativo. (función miembro pública) |
[editar]Ejemplo
condition_variable
se usa en combinación con un std::mutex para facilitar la comunicación intrahilos.
#include <iostream>#include <string>#include <thread>#include <mutex>#include <condition_variable> std::mutex m; std::condition_variable cv;std::string datos;bool listo =false;bool procesados =false; void hilo_obrero(){// Esperar hasta que main() mande datosstd::unique_lock<std::mutex> lk(m); cv.wait(lk, []{return listo;}); // después de la espera, tenemos posesión del cerrojo.std::cout<<"Hilo obrero procesando datos\n"; datos +=" después de procesar"; // Enviar datos de vuelta a main() procesados =true;std::cout<<"Hilo obrero indica procesamiento de datos completo\n"; // Se hace un desbloqueo manual antes de notificar, para evitar despertar// el hilo en espera solo para bloquearse de nuevo (véase notify_one para detalles) lk.unlock(); cv.notify_one();} int main(){std::thread obrero(hilo_obrero); datos ="Datos de ejemplo";// enviar datos al hilo obrero{std::lock_guard<std::mutex> lk(m); listo =true;std::cout<<"main() indica datos listos para procesar\n";} cv.notify_one(); // esperar al hilo obrero{std::unique_lock<std::mutex> lk(m); cv.wait(lk, []{return procesados;});}std::cout<<"De vuelta en main(), datos = "<< datos <<'\n'; obrero.join();}
Salida:
main() indica datos listos para procesar Hilo obrero procesando datos Hilo obrero indica procesamiento de datos completo De vuelta en main(), datos = Datos de ejemplo después de procesar