2013-06-03 13 views
11

Ho scritto un programma multi-thread con pthread, usando il modello produttore-consumatore.Pthread Mutex: pthread_mutex_unlock() consuma un sacco di tempo

Quando uso il profiler Intel VTune per profilare il mio programma, ho trovato che il produttore e il consumatore passano molto tempo su pthread_mutex_unlock. Non capisco perché sia ​​successo. Penso che i thread potrebbero aspettare molto prima che possano acquisire un mutex, ma rilasciare un mutex dovrebbe essere veloce, giusto?

L'istantanea di seguito è tratta da Intel VTune. Mostra i codici in cui il consumatore tenta di recuperare un elemento dal buffer e il tempo impiegato da ogni riga di codice.

La mia domanda è: perché pthread_mutex_unlock ha un simile sovraccarico? Il problema è con il pthread mutex stesso o con il modo in cui lo utilizzo? enter image description here

+0

Lo sblocco di un mutex può essere lento se c'è un sacco di contesa su quel mutex, perché parte del lavoro di sblocco sta svegliando qualsiasi thread in attesa sul mutex. – caf

+6

Penso che sarebbe interessante vedere i risultati se si sposta la chiamata 'pthread_mutex_unlock()' sopra la chiamata a 'pthread_cond_signal()'. Non c'è alcun obbligo di tenere il mutex mentre segnala la variabile di condizione (solo quando lo si aspetta), e sospetto che ciò che accade sia che il segnale causi conflitto sul mutex perché il thread che viene rilasciato tenta immediatamente di acquisire il mutex, che il il filo di segnalazione rimane fermo. –

+2

@MichaelBurr Buon punto! Esamino il tuo suggerimento e il programma è ora più veloce del 40%. –

risposta

2

La funzione pthread_mutex_unlock() deve rilasciare l'oggetto mutex a cui fa riferimento mutex. Ma il modo in cui un mutex viene rilasciato dipende dall'attributo type del mutex. Se sono presenti thread bloccati sull'oggetto mutex a cui fa riferimento mutex quando viene chiamato pthread_mutex_unlock(), il risultato della mutex diventa disponibile, la politica di pianificazione determina quale thread acquisirà il mutex.

Se il tipo di mutex è PTHREAD_MUTEX_NORMAL, il rilevamento del deadlock non deve essere fornito. Il tentativo di bloccare il mutex provoca un deadlock. Se un thread tenta di sbloccare un mutex che non ha bloccato o un mutex che è sbloccato, si ottiene un comportamento indefinito.

Se il tipo di mutex è PTHREAD_MUTEX_ERRORCHECK, è necessario fornire un controllo degli errori. Se un thread tenta di ricollegare un mutex che ha già bloccato, verrà restituito un errore. Se un thread tenta di sbloccare un mutex che non ha bloccato o un mutex che è sbloccato, deve essere restituito un errore.

Se il tipo di mutex è PTHREAD_MUTEX_RECURSIVE, il mutex deve mantenere il concetto di un conteggio di blocco. Quando un thread acquisisce con successo un mutex per la prima volta, il conto di blocco deve essere impostato su uno. Ogni volta che un thread ricollega questo mutex, il conteggio dei blocchi deve essere incrementato di uno. Ogni volta che il thread sblocca il mutex, il numero di blocchi verrà decrementato di uno. Quando il conteggio dei blocchi raggiunge lo zero, il mutex diventa disponibile per altri thread da acquisire. Se un thread tenta di sbloccare un mutex che non ha bloccato o un mutex che è sbloccato, deve essere restituito un errore.

Se il tipo di mutex è PTHREAD_MUTEX_DEFAULT, il tentativo di bloccare in modo ricorsivo i risultati mutex nel comportamento non definito. Il tentativo di sbloccare il mutex se non è stato bloccato dal thread chiamante determina un comportamento indefinito. Il tentativo di sbloccare il mutex se non è bloccato determina un comportamento indefinito.

Di solito preferisco usare i mutex PTHREAD_MUTEX_RECURSIVE, perché in questo caso il mutex diventa disponibile quando il conteggio raggiunge lo zero e il thread chiamante non ha più blocchi su questo mutex.