Pregunta

¿Hay alguna desventaja en llamar a pthread_cond_timedwait sin tomar un bloqueo en el mutex asociado primero y también no tomar un bloqueo de mutex cuando se llama pthread_cond_signal?

En mi caso, no hay ninguna condición para verificar, quiero un comportamiento muy similar a Java wait (long) y notify ().

Según la documentación, puede haber un "comportamiento de programación impredecible". No estoy seguro de lo que eso significa.

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

¿Fue útil?

Solución

El primero no está bien:

  

El pthread_cond_timedwait () y   Las funciones pthread_cond_wait () deberán   Bloque en una variable de condición. Ellos   se llamará con mutex bloqueado por   el hilo de llamada o indefinido   resultados de comportamiento.

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

La razón es que la implementación puede querer confiar en que el mutex esté bloqueado para agregarlo de manera segura a una lista de camareros. Y es posible que desee liberar el mutex sin verificar primero que esté retenido.

El segundo es molesto:

  

si el comportamiento de programación predecible es   requerido, entonces ese mutex está bloqueado por   el hilo llamando    pthread_cond_signal () o    pthread_cond_broadcast () .

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

Desde lo alto de mi cabeza, no estoy seguro de cuál es la condición específica de la carrera que desordena el comportamiento del programador si haces la señal sin tomar el bloqueo. Por lo tanto, no sé qué tan malo puede ser el comportamiento del programador indefinido: por ejemplo, tal vez con la difusión, los meseros simplemente no obtienen el bloqueo en orden de prioridad (o, sin embargo, su programador en particular se comporta). O tal vez los camareros pueden "perderse".

Sin embargo, en general, con una variable de condición desea establecer la condición (al menos una bandera) y la señal, en lugar de solo una señal, y para esto necesita tomar el mutex. La razón es que, de lo contrario, si eres concurrente con otro hilo que llama a wait (), entonces obtienes un comportamiento completamente diferente según si gana () o la señal () gana: si la señal () se cuela primero, entonces espere el tiempo de espera completo aunque la señal que le interesa ya haya sucedido. Eso rara vez es lo que quieren los usuarios de variables de condición, pero puede estar bien para usted. Quizás esto es lo que significan los documentos por " comportamiento del programador impredecible " - De repente, el intervalo de tiempo se vuelve crítico para el comportamiento de su programa.

Por cierto, en Java debe tener el bloqueo para notificar () o notificar a Todos ():

  

Este método solo debe ser llamado por un   hilo que es el dueño de este   monitor del objeto.

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

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

Otros consejos

La excelente "programación de Butenhof con hilos POSIX" analiza esto justo al final del capítulo 3.3.3.

Básicamente, la señalización del condvar sin bloquear el mutex es una optimización de rendimiento de potencial : si el hilo de señalización tiene el mutex bloqueado, entonces el hilo que se activa en el condvar tiene que bloquear inmediatamente en el mutex que el hilo de señalización se ha bloqueado incluso si el hilo de señalización no está modificando ninguno de los datos que usará el hilo de espera.

La razón por la que "el comportamiento impredecible del planificador" Se menciona 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 menor prioridad puede venir y bloquear el mutex para que cuando el condvar esté señalizado y el hilo de alta prioridad se despierta, tiene que esperar en el hilo de menor prioridad para liberar el mutex. Si el mutex está bloqueado durante la señalización, entonces el subproceso de mayor prioridad se programará en el mutex antes del subproceso de menor prioridad: básicamente lo sabrá cuando se "despierte". el subproceso de alta prioridad se activará tan pronto como el planificador lo permita (por supuesto, es posible que tenga que esperar en el mutex antes de señalar el subproceso de alta prioridad, pero ese es un problema diferente).

El punto de espera en la variable condicional emparejada con un mutex es atómicamente ingresar a wait y liberar el bloqueo, es decir, permitir que otros hilos modifiquen el estado protegido, luego nuevamente recibir atómicamente notificación del cambio de estado y adquirir la cerradura. Lo que describe se puede hacer con muchos otros métodos, como tuberías, enchufes, señales o, probablemente, el más apropiado: semáforos .

Creo que esto debería funcionar (tenga en cuenta el 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

Las condiciones deben indicarse fuera del mutex siempre que sea posible. Los mutex 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 proteger el acceso a algunas variables compartidas en el programa para que se comporten de forma atómica. Cuando se realiza una operación de señalización dentro de un mutex, se incluyen cientos de ciclos irrelevantes de la máquina en el mutex que no tienen nada que ver con proteger los datos compartidos. Potencialmente, llama desde un espacio de usuario hasta un núcleo.

Las notas sobre " comportamiento previsible del planificador " En el estándar son completamente falsos.

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

Usamos 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 que se deben realizar, como una respuesta más oportuna a eventos en tiempo real o cómputo en múltiples procesadores.

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

La conclusión es que la ubicació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, de repente, el programa tiene exactamente el mismo comportamiento reproducible en todas las plataformas.

" comportamiento de programación impredecible " significa solo 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 bloquearse.

Básicamente, si algún documento sugiere que algo indefinido / impredecible puede suceder a menos que haga lo que los documentos le dicen que haga, será mejor que lo haga. Otras cosas podrían 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)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top