2009-06-16 18 views
6

¿Hay alguna desventaja al llamar a pthread_cond_timedwait sin tener que bloquear primero el mutex asociado, y tampoco tomar un bloqueo de exclusión mutua al llamar a pthread_cond_signal?No se bloquea mutex para pthread_cond_timedwait y pthread_cond_signal (en Linux)

En mi caso no es realmente ninguna condición para comprobar, quiero un comportamiento muy similar al de Java de espera (tiempo) y notificar().

Según la documentación, no puede haber "comportamientos de programación impredecible". No estoy seguro de qué significa eso.

Un ejemplo de programa parece funcionar bien sin bloquear las exclusiones mutuas primera.

+0

para que quede claro, lo que quiere es esperar hasta N segundos, a menos que se despierte temprano? –

+0

sí solo eso. Probablemente los semáforos son un mejor trato. –

Respuesta

11

El primero no está bien:

Los pthread_cond_timedwait() y pthread_cond_wait() funciones serán bloque de una condición variable. Ellos serán llamados con mutex bloqueado por el subproceso de llamada o no definido resultados de comportamiento.

http://opengroup.org/onlinepubs/009695399/functions/pthread_cond_timedwait.html

La razón es que la aplicación puede querer depender de la exclusión mutua estar encerrado con el fin de agregar con seguridad a una lista camarero. Y es posible que desee liberar el mutex sin verificar primero que esté retenido.

El segundo es inquietante:

si se requiere comportamientos de programación predecible , a continuación, que mutex está bloqueado por el subproceso de llamada pthread_cond_signal() o pthread_cond_broadcast().

http://www.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_signal.html

De la parte superior de mi cabeza, no estoy seguro de lo que la condición de carrera específica es que meta la pata comportamiento del programador si la señal sin tomar la cerradura. Así que no sé qué tan malo puede ser el comportamiento indefinido del programador: por ejemplo, tal vez con la transmisión, los camareros simplemente no obtienen el bloqueo en orden de prioridad (o sin embargo, su programador particular normalmente se comporta). O tal vez los camareros pueden "perderse".

general, sin embargo, con una condición variable que desea establecer la condición (al menos una bandera) y la señal, en lugar de sólo la señal, y por ello, tiene que tomar la exclusión mutua. La razón es que, de lo contrario, si estás concurrente con otro hilo que llama a wait(), entonces obtienes un comportamiento completamente diferente en función de si wait() o signal() gana: si la señal() se cuela primero, entonces podrás espere el tiempo de espera completo aunque la señal que le importa ya haya sucedido. Rara vez es lo que quieren los usuarios de las variables de condición, pero puede estar bien para ti. Tal vez esto es lo que los documentos significan con "comportamiento impredecible del planificador": de repente, el tiempo se vuelve crítico para el comportamiento de su programa.

Por cierto, en Java que tiene que tener la cerradura con el fin de notificar() o notifyAll():

Este método sólo debe ser llamado por un hilo que es el propietario del monitor de este del objeto .

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html#notify()

El Java sincronizado {/}/wait/notifty/notifyAll comportamiento es análogo al pthread_mutex_lock/pthread_mutex_unlock/pthread_cond_wait/pthread_cond_signal/pthread_cond_broadcast, y no por casualidad.

+0

Es posible que desee corregir el enlace al JavaDoc ... el paréntesis debe ser parte de la URL. –

+1

Java arroja si el monitor no es propiedad del hilo correcto. – Arkadiy

+2

Creo que todo lo que significa es que cuando modificas la condición, liberas el bloqueo, otro hilo (llámalo B) puede tomar el mutex, verificar la condición y ver que está señalizado, y actuar sobre eso. Mientras tanto, cond_signal() está disparando y el otro hilo (llámelo A) que podría verificar los bloques de condición que intentan bloquear el mutex. Cuando A finalmente agarra el mutex, ve que B ya reinició la condición y vuelve a dormir nuevamente en cond_wait. Si todos los hilos son "iguales", es inofensivo, pero en teoría el hilo A podría morir de hambre. –

3

El punto de espera en la variable condicional emparejado con un mutex es atómicamente entrar esperar y liberar el bloqueo, es decir, permitir que otros hilos para modificar el estado protegido, y luego recibir de nuevo atómicamente notificación del cambio de estado y adquirir el bloqueo . Lo que describes se puede hacer con muchos otros métodos, como tubos, tomas de corriente, señales o, probablemente el más apropiado, semáforos.

1

creo que esto debería funcionar (nota código no probado):

// initialize a semaphore 
sem_t sem; 
sem_init(&sem, 
    0, // not shared 
    0 // initial value of 0 
    ); 


// thread A 
struct timespec tm; 
struct timeb tp; 

const long sec  = msecs/1000; 
const long millisec = msecs % 1000; 

ftime(&tp); 
tp.time += sec; 
tp.millitm += millisec; 
if(tp.millitm > 999) { 
    tp.millitm -= 1000; 
    tp.time++; 
} 
tm.tv_sec = tp.time; 
tm.tv_nsec = tp.millitm * 1000000; 

// wait until timeout or woken up 
errno = 0; 
while((sem_timedwait(&sem, &tm)) == -1 && errno == EINTR) { 
    continue; 
} 

return errno == ETIMEDOUT; // returns true if a timeout occured 


// thread B 
sem_post(&sem); // wake up Thread A early 
+0

+1, aunque tenga en cuenta que sem_timed_wait es opcional. Con lo cual me refiero a más optativos que los semáforos, que a su vez también son opcionales, pero no tiene mucho sentido tener pthreads sin ellos ... –

-1

"comportamientos de programación impredecible" significa precisamente eso. No sabes lo que va a pasar. Tampoco la implementación. Podría funcionar como se esperaba. Podría bloquear tu aplicación. Podría funcionar bien durante años, luego una condición de carrera hace que tu aplicación se convierta en mono. Podría estancarse.

Básicamente, si alguna documentos sugieren nada indefinido/unpredicatble puede suceder a menos que hagas lo que los doctores le dicen que hacer, es mejor hacerlo. Otras cosas pueden explotar en tu cara. (Y no explotará hasta que ponga el código en producción, solo para molestarlo aún más. Al menos esa es mi experiencia)

+2

No estoy de acuerdo. El significado de "comportamiento impredecible del planificador" es ambiguo, pero estoy bastante seguro de que la intención no es implicar un "comportamiento indefinido", o lo hubieran dicho como lo hacen en pthread_cond_wait. –

9

La excelente programación de Butenhof "con hilos POSIX" discute este derecho al final del capítulo 3.3 .3.

Básicamente, lo que indica la condvar sin bloquear el mutex es un potencial de optimización rendimiento : si el hilo de señalización tiene el mutex bloqueado, entonces el hilo de vigilia en el condvar tiene que bloquear inmediatamente en el mutex que el hilo de señalización ha bloqueado incluso si el hilo de señalización no modifica ninguno de los datos que usará el hilo de espera. El motivo por el que se menciona el "comportamiento impredecible del planificador" es que si tiene un subproceso de alta prioridad esperando en el condvar (que otro subproceso va a señalar y activará el subproceso de alta prioridad), cualquier otro subproceso de prioridad más baja. puede venir y bloquear el mutex de modo que cuando se señala el condvar y se despierta el subproceso de alta prioridad, tiene que esperar en el subproceso de menor prioridad para liberar el mutex. Si el mutex está bloqueado durante la señalización, el subproceso de mayor prioridad se programará en el mutex antes del subproceso de menor prioridad: básicamente, usted sabe que cuando "despierta" el subproceso de alta prioridad se activará tan pronto como el planificador lo permite (por supuesto, puede que tenga que esperar en el mutex antes de señalar el hilo de alta prioridad, pero ese es un problema diferente).

+0

+1 para obtener una buena explicación de los elusivos "¿por qué debería bloquear el mutex para la señalización de var de condición?" ¡problema! –

+0

La señalización del condvar sin un bloqueo de exclusión mutua no es solo una optimización potencial. Estás sacando cientos de ciclos innecesarios de la máquina de la cerradura. – Kaz

+0

@Kaz: si está eliminando los ciclos de la máquina de la cerradura y la ha optimizado en el nivel micro, pero si tiene la inversión de prioridad resultante y su subproceso de alta prioridad está esperando subprocesos de menor prioridad, es probable que tenga una programa subóptimo. – TheJuice

0

Las condiciones se deben señalar fuera del mutex siempre que sea posible. Los mutexes son un mal necesario en la programación concurrente. Su uso conduce a una disputa que le roba al sistema el máximo rendimiento que puede obtener del uso de múltiples procesadores.

El propósito de un mutex es para proteger el acceso a algunas variables compartidas en el programa para que se comporten de forma atómica. Cuando una operación de señalización se realiza dentro de un mutex, provoca la inclusión de cientos de ciclos de máquina irrelevantes en el mutex que no tienen nada que ver con la protección de los datos compartidos. Potencialmente, llama desde un espacio de usuario hasta un kernel.

Las notas sobre "comportamiento predecible del programador" en el estándar son completamente falsas.

Cuando queremos que la máquina ejecute sentencias en un orden predecible y bien definido, la herramienta para eso es la secuencia de sentencias dentro de un único hilo de ejecución: S1 ; S2. La declaración S1 está "programada" antes del S2.

Utilizamos subprocesos cuando nos damos cuenta de que algunas acciones son independientes y su orden de programación no es importante, y hay beneficios de rendimiento, como una respuesta más oportuna a los eventos en tiempo real o la computación en múltiples procesadores.

En momentos en que las órdenes de programación se vuelven importantes entre varios hilos, esto cae bajo un concepto llamado prioridad . La prioridad resuelve lo que sucede primero cuando cualquiera de las declaraciones N podría ser programada para ejecutarse. Otra herramienta para ordenar bajo multihilo es hacer cola. Los eventos se colocan en una cola por uno o más subprocesos y un solo subproceso de servicio procesa los eventos en el orden de cola.

La conclusión es que la colocación de pthread_cond_broadcast no es una herramienta adecuada para controlar el orden de ejecución. No hará que el orden de ejecución sea predecible en el sentido de que el programa de repente tiene exactamente el mismo comportamiento reproducible en cada plataforma.

Cuestiones relacionadas