Para citar la página del manual:
Cuando se usan variables de condición, siempre hay un predicado booleano que involucra variables compartidas asociadas con cada espera de condición que es verdadero si el hilo debe continuar. Pueden ocurrir activaciones espurias de las funciones pthread_cond_timedwait () o pthread_cond_wait (). Dado que el retorno de pthread_cond_timedwait () o pthread_cond_wait () no implica nada sobre el valor de este predicado, el predicado debe ser reevaluado en dicho retorno.
Por lo tanto, pthread_cond_wait
puede regresar incluso si no lo ha señalado. A primera vista, al menos, eso parece bastante atroz. Sería como una función que devolvió aleatoriamente el valor incorrecto o regresó aleatoriamente antes de que realmente alcanzara una declaración de retorno adecuada. Parece un error importante. Pero el hecho de que eligieron documentar esto en la página del manual en lugar de corregirlo parece indicar que hay una razón legítima por la que pthread_cond_wait
termina despertando espuriosamente. Presumiblemente, hay algo intrínseco en su funcionamiento que hace que no se pueda evitar. La pregunta es qué.
¿ Por quépthread_cond_wait
vuelve espuriamente? ¿Por qué no puede garantizar que solo se despertará cuando se haya señalado correctamente? ¿Alguien puede explicar la razón de su comportamiento espurio?
pthread_cond_(timed)wait
: "Si se entrega una señal ... el hilo se reanuda esperando la variable de condición como si fuera no se interrumpe, o devolverá cero debido a la activación espuria ". Otras funciones de bloqueo indicanEINTR
cuando se interrumpe por una señal (pread
. Ej. ), O se requiere que se reanuden (ppthread_mutex_lock
. Ej .). Entonces, si no hubiera otras razones para el despertar espurio,pthread_cond_wait
podría haberse definido como cualquiera de esos.Respuestas:
David R. Butenhof da la siguiente explicación en "Programación con hilos POSIX" (p. 80):
En la siguiente discusión de comp.programming.threads , él amplía el pensamiento detrás del diseño:
fuente
Hay al menos dos cosas que podría significar 'despertar espurio':
pthread_cond_wait
puede volver de la llamada a pesar de que no hay ninguna llamada apthread_call_signal
opthread_cond_broadcast
en la condición haya ocurrido.pthread_cond_wait
rendimientos debido a una llamada apthread_cond_signal
opthread_cond_broadcast
, sin embargo después de readquirir el mutex el predicado subyacente se encuentra que ya no es cierto.Pero el último caso puede ocurrir incluso si la implementación de la variable de condición no permite el primer caso. Considere una cola de consumidor productor y tres hilos.
pthread_cond_wait
y bloques en la llamada en espera de señal / transmisión.Por lo tanto, dado que siempre necesita verificar el predicado bajo un bucle, no hay diferencia si las variables de condición subyacentes pueden tener otros tipos de activaciones espurias.
fuente
pthread_cond_signal/broadcast
y no podrás hacerlo, hasta que el mutex se desbloquee llamandopthread_cond_wait
.La sección "Múltiples despertares por señal de condición" en pthread_cond_signal tiene una implementación de ejemplo de pthread_cond_wait y pthread_cond_signal que involucra despertadores espurios.
fuente
Si bien no creo que se haya considerado en el momento del diseño, aquí hay una razón técnica real: en combinación con la cancelación de subprocesos, hay condiciones bajo las cuales puede ser absolutamente necesario tomar la opción de despertar "espuriosamente", al menos a menos que usted estamos dispuestos a imponer restricciones muy muy fuertes sobre qué tipo de estrategias de implementación son posibles.
El problema clave es que, si un hilo actúa sobre la cancelación mientras está bloqueado
pthread_cond_wait
, los efectos secundarios deben ser como si no consumiera ninguna señal en la variable de condición. Sin embargo, es difícil (y altamente restrictivo) asegurarse de que no haya consumido una señal cuando comience a actuar en la cancelación, y en esta etapa puede ser imposible "volver a publicar" la señal en la variable de condición, ya que puede estar en una situación en la que la persona que llamapthread_cond_signal
ya está justificada por haber destruido el condvar y haber liberado la memoria en la que residía.La asignación para la estela espuria te da una salida fácil. En lugar de continuar actuando sobre la cancelación cuando llega mientras está bloqueado en una variable de condición, si ya ha consumido una señal (o si desea ser perezoso, pase lo que pase), puede declarar que ha ocurrido una estela espuria. y volver con exito. Esto no interfiere en absoluto con la operación de cancelación, porque una persona que llama correctamente simplemente actuará en la cancelación pendiente la próxima vez que realice un bucle y
pthread_cond_wait
vuelva a llamar .fuente