2009-03-19 12 views
6

Mam dziwny problem. Mam następujący kod:pthread_cond_timedwait wraca natychmiast

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 połączeń gettimeofday przed każdym wierszu i poprzedza wiersz z czasem. Wynika to w następujący wynik:

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

Jak widać, tylko 7 mikrosekund przekazywane pomiędzy dwoma liniami debugowania, jeszcze pthread_cond_timedwait powrócił ETIMEDOUT. Jak to się może stać? Próbowałem nawet ustawić zegar na coś innego podczas inicjowania zmiennej 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); 

(żaden z komunikatów o błędach nie został wydrukowany). Próbowałem zarówno CLOCK_REALTIME i CLOCK_MONOTONIC.

Ten kod jest częścią kolejki blokującej. Potrzebuję funkcjonalności takiej, że jeśli nic nie zostanie umieszczone w tej kolejce w ciągu 5 sekund, dzieje się coś innego. Muteks i cond są inicjowane, ponieważ kolejka blokująca działa dobrze, jeśli nie używam pthread_cond_timedwait.

Odpowiedz

14

pthread_cond_timedwait zajmuje czas bezwzględny, a nie względny. Musisz ustawić czas oczekiwania na bezwzględny, dodając bieżący czas do wartości limitu czasu.

+0

Och, mam. Możesz użyć pthread_get_expiration_np(), aby dowiedzieć się, jaki jest czas abs. – Claudiu

+3

@ Claudiu pthread_get_expiration_np() nie jest dostępny na moim GNU/Linux. Zamiast tego musiałem: 'timeval now; gettimeofday (i teraz, NULL); long int abstime_ns_large = now.tv_usec * 1000 + delay_ns; timespec abstime = {teraz.tv_sec + (abstime_ns_large/1000000000), abstime_ns_large% 1000000000}; 'gdzie delay_ns jest żądanym opóźnieniem w nanosekundach.Następnie użyj abstime w swoim wywołaniu pthread_cond_timedwait. –

3

Zmienna warunku może niesłusznie odblokować. Musisz sprawdzić to w pętli i sprawdzić stan za każdym razem. Prawdopodobnie będziesz również musiał zaktualizować wartość limitu czasu.

Znalazłem dokumentację dla pthread_cond_timedwaithere.

Przy zastosowaniu zmiennych warunkowych tam zawsze jest logiczna orzecznik udziałem współdzielone zmienne związane z każdego stanu czekać to prawda jeśli wątek powinien postępować. Niepożądane Budziki z funkcji pthread_cond_timedwait() lub pthread_cond_wait() mogą wystąpić . Ponieważ zwrot z pthread_cond_timedwait() lub pthread_cond_wait() nie implikuje niczego na temat wartości tego predykatu , predykat powinien być ponownie oceniony po takim zwrocie.

7

Przepełnienie w timespec jest zwykle przyczyną dziwnych przekroczeń czasu.
Sprawdź 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

Jak już wspomniano w innych odpowiedzi trzeba wykorzystać czas absolutny. Od C11 możesz użyć timespec_get().

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

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