variable pthread_cond_wait pthread_cond_t pthread ejemplo c pthreads

pthread_cond_t - ¿Por qué pthread_cond_wait tiene wakeup espías?



man pthread_cond_wait (3)

Para citar la página man:

Cuando se usan variables de condición, siempre hay un predicado booleano que involucra variables compartidas asociadas con cada condición, que es verdadera si el hilo debe continuar. Pueden aparecer fallas 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 volver a evaluarse a partir de dicho retorno.

Entonces, pthread_cond_wait puede regresar incluso si no lo has señalado. A primera vista al menos, eso parece bastante atroz. Sería como una función que devuelve aleatoriamente el valor incorrecto o que se devuelve aleatoriamente antes de llegar realmente a una declaración de devolución 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 cual pthread_cond_wait termina despertando de forma espuria. Presumiblemente, hay algo intrínseco sobre cómo funciona que lo hace para que eso no se pueda evitar. La pregunta es qué.

¿ Por qué pthread_cond_wait regresa falsamente? ¿Por qué no puede garantizarse que solo se va a activar cuando se haya indicado correctamente? ¿Alguien puede explicar la razón de su comportamiento espurio?


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

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

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 de productor y tres hilos.

  • El subproceso 1 acaba de quitarle la cola a un elemento y lo liberó, y la cola ahora está vacía. El hilo está haciendo lo que haga con el elemento que adquirió en alguna CPU.
  • El subproceso 2 intenta dequeuear un elemento, pero encuentra que la cola está vacía cuando está marcada debajo del mutex, llama a pthread_cond_wait y bloquea la llamada en espera de señal / emisión.
  • El subproceso 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 en la condición, está programado para ejecutarse.
  • Sin embargo, antes de que el subproceso 2 logre entrar en la CPU y tomar el bloqueo de cola, el subproceso 1 completa su tarea actual y vuelve a la cola para más trabajo. Obtiene el bloqueo de cola, verifica el predicado y descubre que hay trabajo en la cola. Continúa para quitar la cola del elemento que insertó el hilo 3, libera el bloqueo y hace lo que haga con el elemento que el hilo 3 puso en cola.
  • El subproceso 2 ahora se conecta a una CPU y obtiene el bloqueo, pero cuando comprueba el predicado, descubre que la cola está vacía. El subproceso 1 ''robó'' el elemento, por lo que el despertador parece espurio. El subproceso 2 necesita esperar nuevamente en la condición.

Por lo tanto, dado que siempre debe verificar el predicado bajo un bucle, no importa si las variables de condición subyacentes pueden tener otros tipos de activaciones espúreas.


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 implica wake-ups falsas.


La siguiente explicación es dada por David R. Butenhof en "Programación con hilos POSIX" (p. 80):

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

En la siguiente discusión comp.programming.threads , él amplía 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 ]-----/