2009-03-19 9 views
6

J'ai un problème étrange. J'ai le code suivant:pthread_cond_timedwait retourner immédiatement

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; 
    } 

dbg appels gettimeofday avant chaque ligne et la ligne avec prepends le temps. Il en résulte la sortie suivante:

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

Comme vous pouvez le voir, seulement 7 microsecondes passé entre les deux lignes de débogage, mais pthread_cond_timedwait retourné ETIMEDOUT. Comment cela peut-il arriver? J'ai même essayé de régler l'horloge à quelque chose d'autre lors de l'initialisation de 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); 

(aucun des messages d'erreur sont imprimés). J'ai essayé les deux CLOCK_REALTIME et CLOCK_MONOTONIC.

Ce code fait partie d'une file d'attente de blocage. J'ai besoin d'une fonctionnalité telle que si rien n'est mis dans cette file d'attente en 5 secondes, il se passe quelque chose d'autre. Le mutex et le cond sont tous deux initialisés, car la file d'attente de blocage fonctionne correctement si je n'utilise pas pthread_cond_timedwait.

Répondre

14

pthread_cond_timedwait prend une heure absolue, pas un temps relatif. Vous devez rendre votre temps d'attente absolu en ajoutant à l'heure actuelle la valeur de votre délai d'attente.

+0

Oh, j'ai compris. Vous pouvez utiliser pthread_get_expiration_np() pour déterminer l'heure abs. – Claudiu

+3

@Claudiu pthread_get_expiration_np() n'est pas disponible sur mon GNU/Linux. Au lieu de cela je devais: 'timeval maintenant; gettimeofday (& maintenant, NULL); long int abstime_ns_large = maintenant.tv_usec * 1000 + delay_ns; timespec abstime = {now.tv_sec + (abstime_ns_large/1000000000), abstime_ns_large% 1000000000}; 'où delay_ns est le délai désiré en nanosecondes.Utilisez ensuite abstime dans votre appel pthread_cond_timedwait. –

3

La variable de condition peut se débloquer de façon erronée. Vous devez vérifier dans une boucle et vérifier la condition à chaque fois. Vous devrez probablement également mettre à jour la valeur du délai d'expiration.

J'ai trouvé de la documentation pour pthread_cond_timedwaithere.

Lorsque vous utilisez les variables de condition, il est toujours un prédicat booléenne impliquant des variables partagées associées à chaque condition attente qui est vrai si le thread doit continuer. Spurious wakeups de la pthread_cond_timedwait() ou pthread_cond_wait() fonctions peuvent se produire. Depuis le retour de pthread_cond_timedwait() ou pthread_cond_wait() ne signifie pas quoi que ce soit au sujet de la valeur de ce prédicat, le prédicat doit être réévalué à ce retour.

7

Le débordement dans timespec est généralement le coupable pour les délais d'expiration étranges.
Vérifier EINVAL:

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

Comme déjà dans d'autres réponses mentionnées, vous devez utiliser le temps absolu. Depuis C11 vous pouvez utiliser timespec_get().

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

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