¿Por qué pthread cond wait tiene wakeups espurios?


Para citar la página de manual:

Cuando se usan variables de condición siempre hay un predicado booleano que involucra variables compartidas asociadas con cada condición wait que es true si el subproceso debe continuar. Pueden ocurrir wakeups espurios 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 sobre tal devolver.

Por lo tanto, pthread_cond_wait puede regresar incluso si no lo ha señalado. Al menos a primera vista, eso parece bastante atroz. Sería como una función que devuelve aleatoriamente el valor incorrecto o devuelve aleatoriamente antes de que realmente alcance una declaración de retorno adecuada. Parece un gran error. Pero el hecho de que hayan elegido documentar esto en la página man en lugar de arreglarlo parecería indicar que hay una razón legítima por la que pthread_cond_wait termina despertando espuriosamente. Presumiblemente, hay algo intrínseco en cómo funciona que hace que eso no se pueda evitar. La pregunta es qué.

por Qué no pthread_cond_wait return falsamente? ¿Por qué no puede garantizar que sólo va a despertar cuando se ha señalado correctamente? ¿Puede alguien explicar la razón de su comportamiento espurio?

 113
Author: Jonathan M Davis, 2011-12-21

3 answers

La siguiente explicación es dada por David R. Butenhof en "Programming with POSIX Threads" (p. 80):

Los wakeups espurios pueden sonar extraños, pero en algunos sistemas multiprocesador, hacer que el wakeup de la condición sea completamente predecible podría ralentizar sustancialmente todas las operaciones de variables de condición.

En el siguiente comp.programación.discusión de hilos , se expande en el pensamiento detrás del diseño:

Patrick Doyle wrote: 
> In article , Tom Payne   wrote: 
> >Kaz Kylheku  wrote: 
> >: It is so because implementations can sometimes not avoid inserting 
> >: these spurious wakeups; it might be costly to prevent them. 

> >But why?  Why is this so difficult?  For example, are we talking about 
> >situations where a wait times out just as a signal arrives? 

> You know, I wonder if the designers of pthreads used logic like this: 
> users of condition variables have to check the condition on exit anyway, 
> so we will not be placing any additional burden on them if we allow 
> spurious wakeups; and since it is conceivable that allowing spurious 
> wakeups could make an implementation faster, it can only help if we 
> allow them. 

> They may not have had any particular implementation in mind. 

You're actually not far off at all, except you didn't push it far enough. 

The intent was to force correct/robust code by requiring predicate loops. This was 
driven by the provably correct academic contingent among the "core threadies" in 
the working group, though I don't think anyone really disagreed with the intent 
once they understood what it meant. 

We followed that intent with several levels of justification. The first was that 
"religiously" using a loop protects the application against its own imperfect 
coding practices. The second was that it wasn't difficult to abstractly imagine 
machines and implementation code that could exploit this requirement to improve 
the performance of average condition wait operations through optimizing the 
synchronization mechanisms. 
/------------------[ [email protected] ]------------------\ 
| Compaq Computer Corporation              POSIX Thread Architect | 
|     My book: http://www.awl.com/cseng/titles/0-201-63392-2/     | 
\-----[ http://home.earthlink.net/~anneart/family/dave.html ]-----/ 

 69
Author: NPE,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-21 18:48:02

Hay al menos dos cosas que 'despertar espurio' podría significar:

  • Un hilo bloqueado en pthread_cond_wait puede regresar de la llamada aunque no se haya producido ninguna llamada para señalar o transmitir la condición.
  • Un subproceso bloqueado en pthread_cond_wait devuelve debido a una llamada a signal o broadcast, sin embargo, después de volver a adquirir el mutex, se encuentra que el predicado subyacente ya no es verdadero.

Pero este ú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.

  • Rosca 1 acaba eliminando un elemento y se libera el mutex, y la cola está vacía. El hilo está haciendo lo que hace con el elemento que adquirió en alguna CPU.
  • Thread 2 intenta desqueuear un elemento, pero encuentra que la cola está vacía cuando está marcada bajo el mutex, llama a pthread_cond_wait, y bloquea en la llamada a la espera de signal/broadcast.
  • El hilo 3 obtiene el mutex, inserta un nuevo elemento en la cola, notifica la variable de condición y libera el bloqueo.
  • En respuesta a la notificación del subproceso 3, el subproceso 2, que estaba esperando la condición, está programado para ejecutarse.
  • Sin embargo, antes de que el subproceso 2 logre entrar en la CPU y agarrar el bloqueo de cola, el subproceso 1 completa su tarea actual y regresa a la cola para más trabajo. Obtiene el bloqueo de cola, comprueba el predicado y encuentra que hay trabajo en la cola. Se procede a dequeue el el elemento que el hilo 3 insertó, libera el bloqueo y hace lo que haga con el elemento que el hilo 3 encolerizó.
  • El hilo 2 ahora entra en una CPU y obtiene el bloqueo, pero cuando comprueba el predicado, encuentra que la cola está vacía. El hilo 1 'robó' el objeto, por lo que el despertar parece ser falso. Hilo 2 necesita esperar en la condición de nuevo.

Así que ya que siempre necesita verificar el predicado bajo un bucle, no hace ninguna diferencia si las variables de condición subyacentes puede tener otro tipo de espurias wakeups.

 78
Author: acm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-21 19:22:29

La sección "Despertares múltiples 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 wakekups espurios.

 7
Author: Jingguo Yao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-17 06:28:31