35 votos

Pthread y esperar las condiciones

Estoy aprendiendo pthread y las condiciones de espera. Como puedo decirle a un típico espera hilo es este:

pthread_mutex_lock(&m);
while(!condition)
     pthread_cond_wait(&cond, &m);
// Thread stuff here
pthread_mutex_unlock(&m);

Lo que no puedo entender es por qué la línea while(!condition) es necesario incluso si utilizo pthread_cond_signal() a despertar el hilo.

Puedo entender que si yo uso pthread_cond_broadcast() necesito condición de prueba, porque me levanto todos los subprocesos en espera y uno de ellos puede hacer que la condición sea falsa de nuevo antes de desbloquear el mutex (y por lo tanto la transferencia de la ejecución a otra despertado hilo que no debe ejecutar en ese momento). Pero si yo uso pthread_cond_signal() me levanto solo un hilo de modo que la condición debe ser cierto. Por lo que el código podría tener este aspecto:

pthread_mutex_lock(&m);
pthread_cond_wait(&cond, &m);
// Thread stuff here
pthread_mutex_unlock(&m);

He leído algo acerca de señales espurias que pueden suceder. Es esto (y sólo ésta) ¿el motivo? ¿Por qué debo tener espurias singnals? O hay algo más no lo entiendo?

Supongo que la señal de código como este:

pthread_mutex_lock(&m);
condition = true;
pthread_cond_signal(&cond); // Should wake up *one* thread
pthread_mutex_unlock(&m);

30voto

nos Puntos 102226

Sí, la pthread api permite espurias despertadores, y esa es la única razón por la que considero que podrían provocar que la necesita para volver a la condición cuando el uso de pthread_cond_signal.

Tal vez una versión en particular en una determinada plataforma de nunca jamás va a causar falsos despertadores, pero cuando los médicos dicen que usted debe volver a comprobar la condición, yo lo haría.

He aquí una manera que hace que espurias despertadores en linux(tomado de wikipedia):

Espurio de reactivación en Linux

El pthread_cond_wait() función en Linux se implementa el uso de la futex llamada al sistema. Cada sistema de bloqueo de llamada en Linux devuelve bruscamente con EINTR cuando el proceso recibe una señal. Un POSIX señal será, por tanto, generar un falso despertar. Este estado no es trivial para arreglar debido a 2 razones:

  • Hacer la señal de la entrega no interrumpir las llamadas al sistema mantiene la pila usada. Si otra llamada al sistema se invoca durante un espacio de usuario de la señal de control de rutina, y que el sistema de llamada se interrumpe demasiado, etc, el núcleo de la pila podría agotarse rápidamente. Volviendo con EINTR permite mantener el uso de la pila bajo control. glibc cheques (o supone) para EINTR después de cada sistema de bloqueo de llamada. El futex estructura de datos que contiene la información suficiente para reiniciar estas llamadas.
  • pthread_cond_wait() no se puede reiniciar la espera porque puede faltar una verdadera reactivación en el poco tiempo que estuvo fuera de la futex llamada al sistema. Esta condición de carrera sólo puede ser evitado por el autor de la llamada de comprobación para un invariante. Para complicar aún más, la especificación POSIX los estados", Estas funciones no se devolverá un código de error de EINTR" ref. Estas funciones devuelven cero en el caso de los falsos wakeup ref, de acuerdo con POSIX.

En contradicción con POSIX, LinuxThreads ("viejo" linux hilos) página man dice que EINTR se devuelve cuando "pthread_cond_timedwait fue interrumpida por una señal". La reciente versión (NPTL) de pthread_cond_timedwait parece mantener a POSIX comportamiento, a pesar de que (volviendo a cero falsos wakeup

30voto

Chris Lu Puntos 211

La verdadera razón por la que usted debe poner pthread_cond_wait en un bucle while no es porque la falsa activación. Incluso si su condición variable no tiene espurias de activación, usted todavía necesita el lazo para atrapar a un tipo común de error. Por qué? Considere la posibilidad de lo que puede suceder si varios hilos de esperar en la misma condición:

Thread 1                         Thread 2           Thread 3
check condition (fails)
(in cond_wait) unlock mutex
(in cond_wait) wait
                                 lock mutex
                                 set condition
                                 signal condvar
                                 unlock mutex
                                                    lock mutex
                                                    check condition (succeeds)
                                                    do stuff
                                                    unset condition
                                                    unlock mutex
(in cond_wait) wake up
(in cond_wait) lock mutex
<thread is awake, but condition
is unset>

El problema aquí es que el hilo debe liberar el mutex antes de esperar, permitiendo potencialmente a otro hilo para "robar" lo que el hilo estaba esperando. A menos que se garantiza que sólo un subproceso puede esperar en esa condición, es incorrecto asumir que la condición es válida para cuando un hilo se despierta.

13voto

Steve Jessop Puntos 166970

Supongamos que usted no se comprueba la condición. A continuación, por lo general, usted no puede evitar de la siguiente mala cosa ocurra (al menos, no se puede evitar en una línea de código):

 Sender                             Receiver
locks mutex
sets condition
signals condvar, but nothing 
  is waiting so has no effect
releases mutex
                                    locks mutex
                                    waits. Forever.

Por supuesto, su segundo ejemplo de código se podría evitar esta haciendo:

pthread_mutex_lock(&m);
if (!condition) pthread_cond_wait(&cond, &m);
// Thread stuff here
pthread_mutex_unlock(&m);

A continuación, sin duda, sería el caso de que si sólo hay cada vez en más de un receptor, y si cond_signal eran lo único que podía despertarlo, entonces sólo se despierta cuando la condición se establece y, por tanto, no se necesita un bucle. nos cubre por qué el segundo "si" no es cierto.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X