pthread_cond_timedwait di tornare immediatamente
-
20-08-2019 - |
Domanda
Sto riscontrando uno strano problema. Ho il seguente codice:
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
chiama gettimeofday
prima di ogni linea e antepone la linea con l'ora. Il risultato è il seguente output:
7.991151: condwait: timeout = 5, 705032704
7.991158: cond timed out
Come puoi vedere, tra le due righe di debug sono passati solo 7 microsecondi, ma pthread_cond_timedwait
ha restituito ETIMEDOUT
. Come può succedere? Ho anche provato a impostare l'orologio su qualcos'altro durante l'inizializzazione della 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 viene stampato). Ho provato sia CLOCK_REALTIME
che CLOCK_MONOTONIC
.
Questo codice fa parte di una coda di blocco. Ho bisogno di funzionalità tali che se non si inserisce nulla in questa coda in 5 secondi, succede qualcos'altro. Il mutex e il cond sono entrambi inizializzati, poiché la coda di blocco funziona bene se non uso <=>.
Soluzione
pthread_cond_timedwait richiede un tempo assoluto, non un tempo relativo. Devi rendere assoluto il tuo tempo di attesa aggiungendo l'ora corrente al tuo valore di timeout.
Altri suggerimenti
L'overflow in timespec
è in genere il colpevole di strani timeout.
Cerca 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;
}
La variabile condizione può sbloccarsi in modo spurio. È necessario controllarlo in un ciclo e controllare la condizione ogni volta. Probabilmente dovrai aggiornare anche il valore di timeout.
Ho trovato della documentazione per pthread_cond_timedwait
qui .
Quando si usano variabili di condizione lì è sempre un predicato booleano coinvolgendo variabili condivise associate con ogni condizione attendere che sia vero se il thread dovesse procedere. spurie sveglia dal pthread_cond_timedwait () o Le funzioni pthread_cond_wait () possono si verificano. Dal momento che il ritorno da pthread_cond_timedwait () o pthread_cond_wait () non implica qualcosa sul valore di questo predicato, il predicato dovrebbe essere rivalutato su tale ritorno.
Come già indicato in altre risposte, devi usare il tempo assoluto. Da C11 puoi usare timespec_get()
.
struct timespec time;
timespec_get(&time, TIME_UTC);
time.tv_sec += 5;
pthread_cond_timedwait(&cond, &mutex, &time);