2011-01-25 16 views
8

Sto codificando in C (in realtà in OOC che viene quindi compilato in C).Come fermarsi e continuare un pthread?

Come faccio a istruire un filo di aspettare in un particolare posto di blocco fino a qualche altro thread gli dice di continuare?

realtà sto usando un loop stretto nel filo e sondaggi una variabile sto cambiando dal thread principale, ma penso che non è ben performante, giusto? Oltre a ciò, quando faccio un ciclo stretto in una discussione, dovrei includere un ciclo di sospensione nel ciclo per evitare di consumare molta potenza della CPU solo in loop?

risposta

10

Sembra che siete alla ricerca di pthread_cond_wait e le sue funzioni correlate.

Ecco una citazione dal manpage con un esempio:

consideri due condiviso variabili xey, protetti dalla mut mutex, ed una condizione cond variabile che deve essere segnalato quando x diventa maggiore y.

  int x,y; 
      pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; 
      pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 

attesa fino a quando x è maggiore di y viene eseguita come segue:

  pthread_mutex_lock(&mut); 
      while (x <= y) { 
        pthread_cond_wait(&cond, &mut); 
      } 
      /* operate on x and y */ 
      pthread_mutex_unlock(&mut); 

modifiche su x ed y che possono causare x diventare maggiore di y deve segnalare la condizione se necessario:

  pthread_mutex_lock(&mut); 
      /* modify x and y */ 
      if (x > y) pthread_cond_broadcast(&cond); 
      pthread_mutex_unlock(&mut); 

Alla fine fa quello che stai chiedendo: il thread che chiama pthread_cond_wait(&cond) è bloccato fino a un altro tre annuncio (il tuo thread principale, ad esempio) chiama pthread_cond_broadcast(&cond). Durante questo periodo è solo in uno stato blocked e non consuma cicli della CPU.

+0

Nota che devi eseguire il ciclo con un ciclo 'while()' come mostrato negli esempi, perché potresti essere svegliato con la condizione non vera. – caf

2

Penso che sia un buon candidato per una condizione. Il thread dovrebbe attendere una condizione e l'altro thread dovrebbe segnalare la condizione per consentire che questo thread continui.

si può cercare pthread_cond_init e che dovrebbe portare ad altre funzioni

2

si dovrebbe guardare in appropriate primitive di sincronizzazione, come mutex, variabili di condizione e semafori. In questo caso, sembra uno condition variable è lo strumento più appropriato dalla libreria pthreads.

1

Solo così si sa cosa stava succedendo, un "loop stretto" consuma riparto della CPU del filo, proprio come qualsiasi altro codice tuo thread esegue. L'unica differenza è che non realizza nulla. Beh, immagino che rendere il nucleo caldo sia qualcosa ... Probabilmente non vorrai mai farlo a meno che non ti interessi il costo dell'interruttore di contesto e sai di sicuro che il tempo di attesa sarà molto più breve del timeslice del tuo thread , che è di circa 1ms. Non so se il sonno sia negativo come rendimento (la resa AFAIK imposta il thread sul retro della lista di thread da attivare al tuo livello di priorità), ma entrambi sostengono almeno la penalità di un interruttore di contesto. C'è un costo per il cambio di contesto. Un interruttore di contesto è ciò che accade quando termina il timeslice del thread. Può terminare perché lo hai terminato con un rendimento o un sonno, o se il kernel l'ha terminato prevenendoti. Leggi su SMP e spinlock per capire di più su interruttori di contesto e casi in cui è applicabile un ciclo stretto.

Inoltre, quando dormi, non sai esattamente quando ti sveglierai di nuovo. quindi una delle ragioni per cui potresti non voler dormire è che devi fare qualcosa velocemente.Potresti aspettare un paio di ms prima di essere riprogrammato.

Tutti gli altri hanno fornito la soluzione pthread_cond_wait, che richiede il blocco tramite mutex e sembra diretta e semplice. Le prestazioni potrebbero essere adeguate alle proprie esigenze, ma sono relativamente lente rispetto a una soluzione che utilizza segnali (sigwait and pthread_kill). La complessità ti insidierà.

Non discusso qui è il motivo per cui si blocca un mutex prima di eseguire il test se è necessario attendere la condizione. La ragione è che il codice come questo ha un difetto:

 while (x <= y) { 
       pthread_cond_wait(&cond, &mut); 
     } 

tuo filo potrebbe verificare (X < = Y), vedere che deve aspettare, ma essere pre-epted prima che si attacca al valore della condizione. Qualche altro thread, che ha appena modificato xey, segnala la condizione in quel timeslice prima che il primo thread sia collegato alla condizione. In questo modo, il segnale di condizione viene perso. Quindi, quello che finisce succede ovunque tu modifichi le variabili che influenzano il segnale, devi aggiungere dei blocchi.

 pthread_mutex_lock(&mut); 
     /* modify x and y */ 
     if (x > y) pthread_cond_broadcast(&cond); 
     pthread_mutex_unlock(&mut); 

Questo può significare che si aggiungono questi blocchi mutex in molti posti diversi e il codice diventa più complesso e più lento a causa di questo. La possibilità di un filo appeso in attesa di una condizione è sempre lì. La soluzione loop, test, sleep non ha nessuno di questi problemi. Quindi, se il tempo di attesa è noto per essere breve, l'uso di sleep in loop è probabilmente una soluzione eccellente. Soprattutto se riesci a dormire per un secondo o più tra un test e l'altro. Se puoi, non preoccuparti di mutex e condizioni. Se il tempo di sonno è breve, come 1ms e il tempo di attesa è lungo, come minuti o ore, allora finirai per sprecare risorse risvegliandoti continuamente e tornando a dormire. Devi giudicare.

Inoltre, tenere presente che a volte il kernel proverà a riattivare immediatamente il thread del cameriere e altre volte ci sarà un ritardo. Se il thread si sveglia troppo presto, si riattiverà mentre il mutex è bloccato e ritorna immediatamente in stato di sospensione fino a quando il mutex non si sblocca. Se questo diventa un problema, segnalare la condizione in questo modo:

pthread_mutex_lock(&mut); 
/* modify x and y */ 
if (x > y) { 
    pthread_mutex_unlock(&mut); 
    pthread_cond_broadcast(&cond); 
} else 
    pthread_mutex_unlock(&mut); 

Ringraziamenti vanno a user576875, che è esempi di codice ho copiato.