c++ - pthread_cond_wait - pthread_cond_t
Llamar a pthread_cond_signal sin bloquear mutex (3)
Leí en alguna parte que deberíamos bloquear el mutex antes de llamar a pthread_cond_signal y desbloquear el texto alternativo después de llamarlo:
La rutina pthread_cond_signal () se usa para señalar (o reactivar) otro subproceso que está esperando la variable de condición. Se debe invocar después de bloquear mutex y debe desbloquear mutex para que se complete la rutina pthread_cond_wait ().
Mi pregunta es: ¿no está bien llamar a los métodos pthread_cond_signal o pthread_cond_broadcast sin bloquear el mutex?
De acuerdo con este manual:
Las funciones
pthread_cond_broadcast()
opthread_cond_signal()
pueden ser llamadas por un hilo, ya sea que posea o no el mutex que los hilos llamadospthread_cond_wait()
opthread_cond_timedwait()
han asociado con la variable de condición durante sus esperas; sin embargo, si se requiere un comportamiento de programación predecible, ese subtexto será bloqueado por el hilo que llama apthread_cond_broadcast()
opthread_cond_signal()
.
Dave Butenhof (autor de Programming with POSIX Threads ) en comp.programming.threads explicó el significado de la declaración de comportamiento de programación predecible y está disponible here .
Si no bloquea el mutex en la ruta de código que cambia la condición y las señales, puede perder los despertadores. Considere este par de procesos:
Proceso A:
pthread_mutex_lock(&mutex);
while (condition == FALSE)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
Proceso B (incorrecto):
condition = TRUE;
pthread_cond_signal(&cond);
Luego considere esta posible intercalación de instrucciones, donde la condition
comienza como FALSE
:
Process A Process B
pthread_mutex_lock(&mutex);
while (condition == FALSE)
condition = TRUE;
pthread_cond_signal(&cond);
pthread_cond_wait(&cond, &mutex);
La condition
ahora es TRUE
, pero el Proceso A está atascado esperando la variable de condición, perdió la señal de activación. Si modificamos el Proceso B para bloquear el mutex:
Proceso B (correcto):
pthread_mutex_lock(&mutex);
condition = TRUE;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
... entonces lo anterior no puede ocurrir; el despertador nunca se perderá.
(Tenga en cuenta que en realidad puede mover la pthread_cond_signal()
después de pthread_mutex_unlock()
, pero esto puede dar como resultado una programación menos óptima de los hilos, y ya ha bloqueado necesariamente el mutex en esta ruta de código debido a la modificación de la condición misma).
caf, en su código de muestra, el Proceso B modifica la condition
sin bloquear primero el mutex. Si el Proceso B simplemente bloqueó el mutex durante esa modificación, y luego aún desbloqueó el mutex antes de llamar a pthread_cond_signal
, no habría ningún problema. ¿Tengo razón al respecto?
Creo intuitivamente que la posición de caf es correcta: llamar a pthread_cond_signal
sin tener el bloqueo de exclusión mutua es una mala idea. Pero el ejemplo de caf no es en realidad evidencia en apoyo de esta posición; es simplemente una evidencia en apoyo de la posición mucho más débil (prácticamente evidente) de que es una mala idea modificar el estado compartido protegido por un mutex a menos que haya bloqueado ese mutex primero.
¿Alguien puede proporcionar algún código de muestra en el que llamar a pthread_cond_signal
seguido de pthread_mutex_unlock
produce un comportamiento correcto, pero llamar a pthread_mutex_unlock
seguido de pthread_cond_signal
produce un comportamiento incorrecto?