2009-03-19 13 views
6

Ho uno strano problema. Ho il seguente codice:pthread_cond_timedwait che restituisce immediatamente

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 chiamate gettimeofday prima di ogni linea e antepone la riga con il tempo. Essa si traduce nel seguente output:

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

Come si può vedere, solo 7 microsecondi passati tra le due linee di debug, ma pthread_cond_timedwait restituito ETIMEDOUT. Come può accadere? Ho anche provato a fissare l'orologio per qualcosa d'altro quando si inizializza la variabile 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); 

(nessuno dei messaggi di errore vengono stampati). Ho provato sia CLOCK_REALTIME e CLOCK_MONOTONIC.

Questo codice è parte di una coda di blocco. Ho bisogno di funzionalità tali che se nulla viene messo in coda in 5 secondi, succede qualcos'altro. Il mutex e il cond sono entrambi inizializzati, poiché la coda di blocco funziona bene se non utilizzo pthread_cond_timedwait.

risposta

14

pthread_cond_timedwait richiede un tempo assoluto, non un tempo relativo. È necessario impostare il tempo di attesa in assoluto aggiungendo all'ora corrente il valore di timeout.

+0

Oh capito. È possibile utilizzare pthread_get_expiration_np() per capire che cos'è il tempo abs. – Claudiu

+3

@Claudiu pthread_get_expiration_np() non è disponibile sulla mia GNU/Linux. Invece ho dovuto: 'ora timida; gettimeofday (& now, 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}; 'dove delay_ns è il ritardo desiderato in nanosecondi.Quindi utilizzare abstime nella chiamata pthread_cond_timedwait. –

3

La variabile di condizione può essere sbloccata in modo errato. È necessario controllarlo in un ciclo e controllare ogni volta le condizioni. Probabilmente dovrai aggiornare anche il valore di timeout.

Ho trovato della documentazione per pthread_cond_timedwaithere.

Quando si utilizzano variabili di condizione ci è sempre un predicato booleano che coinvolgono le variabili condivise associate con ogni condizione di attesa che è vero se il thread dovrebbe procedere. Spurious wakeup da pthread_cond_timedwait() o pthread_cond_wait() potrebbero verificarsi funzioni. Dal momento che il ritorno da pthread_cond_timedwait() o pthread_cond_wait() non implica predicato, il predicato dovrebbe essere rivalutato al ritorno.

7

Trabocco in timespec è di solito il colpevole per i timeout strani.
Controllare 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

come già in altre risposte menzionato è necessario utilizzare il tempo assoluto. Dal momento che C11 è possibile utilizzare timespec_get().

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

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