2009-03-19 9 views
6

Tengo un problema extraño. Tengo el siguiente código:pthread_cond_timedwait que vuelve inmediatamente

dbg("condwait: timeout = %d, %d\n", 
     abs_timeout->tv_sec, abs_timeout->tv_nsec); 
    ret = pthread_cond_timedwait(&q->q_cond, &q->q_mtx, abs_timeout); 
    if (ret == ETIMEDOUT) 
    { 
     dbg("cond timed out\n"); 
     return -ETIMEDOUT; 
    } 

dbggettimeofday llamadas antes de cada línea y antepone la línea con el tiempo. El resultado es el siguiente resultado:

7.991151: condwait: timeout = 5, 705032704 
    7.991158: cond timed out 

Como se puede ver, sólo 7 microsegundos pasaron entre las dos líneas de depuración, sin embargo pthread_cond_timedwait regresaron ETIMEDOUT. ¿Cómo puede pasar esto? Incluso he intentado ajustar el reloj a otra cosa cuando se inicializa la variable cond:

int ret; 
ret = pthread_condattr_init(&attributes); 
if (ret != 0) printf("CONDATTR INIT FAILED: %d\n", ret); 
ret = pthread_condattr_setclock(&attributes, CLOCK_REALTIME); 
if (ret != 0) printf("SETCLOCK FAILED: %d\n", ret); 
ret = pthread_cond_init(&q->q_cond, &attributes); 
if (ret != 0) printf("COND INIT FAILED: %d\n", ret); 

(ninguno de los mensajes de error se imprime). Intenté ambos CLOCK_REALTIME y CLOCK_MONOTONIC.

Este código es parte de una cola de bloqueo. Necesito una funcionalidad tal que si no se pone nada en esta cola en 5 segundos, ocurra algo más. El mutex y el cond se inicializan, ya que la cola de bloqueo funciona bien si no utilizo pthread_cond_timedwait.

Respuesta

14

pthread_cond_timedwait toma un tiempo absoluto, no un tiempo relativo. Debe hacer que su tiempo de espera sea absoluto agregando la hora actual al valor de tiempo de espera.

+0

Oh, lo tengo. Puede usar pthread_get_expiration_np() para averiguar cuál es el tiempo de abs. – Claudiu

+3

@Claudiu pthread_get_expiration_np() no está disponible en mi GNU/Linux. En cambio, tuve que: 'timeval ahora; gettimeofday (y ahora, NULL); long int abstime_ns_large = now.tv_usec * 1000 + delay_ns; timespec abstime = {now.tv_sec + (abstime_ns_large/1000000000), abstime_ns_large% 1000000000}; 'donde delay_ns es el retardo deseado en nanosegundos.A continuación, utilice un período de cinco minutos en su llamada pthread_cond_timedwait. –

3

La variable de condición puede desbloquearse de forma espuria. Debe verificarlo en un bucle y verificar la condición cada vez que lo haga. Probablemente necesites actualizar el valor de tiempo de espera también.

Encontré documentación para pthread_cond_timedwaithere.

Al utilizar variables de condición no siempre es un predicado de Boole que involucra variables compartidas asociadas con cada condición esperar eso es cierto si el hilo debe proceder. Las espurias de las pthread_cond_timedwait() o pthread_cond_wait() pueden ocurrir funciones . 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 en dicho retorno.

7

Overflow en timespec suele ser el culpable de tiempos de espera extraños.
Comprobar si EINVAL: ya

void timespec_add(struct timespec* a, struct timespec* b, struct timespec* out) 
{ 
    time_t sec = a->tv_sec + b->tv_sec; 
    long nsec = a->tv_nsec + b->tv_nsec; 

    sec += nsec/1000000000L; 
    nsec = nsec % 1000000000L; 

    out->tv_sec = sec; 
    out->tv_nsec = nsec; 
} 
0

Como en otras respuestas se menciona que tiene que utilizar el tiempo absoluto. Desde C11 puede usar timespec_get().

struct timespec time; 
timespec_get(&time, TIME_UTC); 
time.tv_sec += 5; 

pthread_cond_timedwait(&cond, &mutex, &time); 
Cuestiones relacionadas