2011-12-29 3 views
5

Sono in esecuzione un programma multithreaded presa con valgrind. Il client invierà una richiesta al server su TCP e quindi occuperà l'attesa su un valore booleano. Il valore booleano verrà impostato quando viene richiamata la funzione di callback che fornisce la risposta dal server. Una volta ricevuta la risposta (e il flag booleano è impostato), il server invierà nuovamente una richiesta e lo farà ripetutamente in un ciclo.bancarelle valgrind in programma presa multithreading

Mi rendo conto che l'accesso non sincronizzato a variabili condivise (il booleano) può causare problemi di threading, ma ho provato a utilizzare i mutex pthread e il programma rallenta di circa il 20% (la velocità è importante qui). Sono fiducioso che scrivere sulla variabile booleana condivisa va bene dato che può essere fatto in un singolo ciclo.

Il programma funziona bene al di fuori di valgrind, ma sarà spesso in stallo se eseguito con valgrind. Ho lasciato il programma in esecuzione durante la notte .. di solito ci vogliono alcuni secondi per completare, quindi non penso che sia un caso di non aspettare abbastanza a lungo per il completamento del programma. Il threading è gestito dal framework del motore open source (quick fix), quindi non penso che sia un problema con il modo in cui i thread sono creati/gestiti.

Qualcuno sa di eventuali problemi con valgrind intorno multi threaded programmi/cicli di attesa occupato/Socket Communications (o una combinazione di questi)?

+1

busy-waiting su una variabile booleana condivisa non è "eseguito in un singolo ciclo", è eseguito in più cicli per iterazione del ciclo e se il ciclo di occupato è in attesa su un round-trip TCP attraverso la rete, quindi il il ciclo probabilmente andrà a ripetersi diversi miliardi di volte (e quindi sprecherà diversi miliardi di cicli di CPU che potrebbero essere stati usati meglio altrove). Una soluzione migliore di entrambe le cose che hai menzionato sarebbe quella di attendere su una variabile di condizione, e fare in modo che la funzione di callback segnali la variabile di condizione per riattivare il thread quando i dati sono pronti. –

+0

Stavo affermando che la scrittura sulla variabile booleana viene eseguita in un singolo ciclo (non l'intero processo di attesa occupato). Detto questo, avrei dovuto dichiarare che scrivere sulla variabile booleana è fatto atomicamente (dato che la cache non riesce, ecc., Può spingere una scrittura di un singolo byte dopo un singolo ciclo della CPU) – Taras

+0

Quello che ha detto Jeremy: l'attesa di lavoro è una cattiva idea, variabile di condizione è meglio, ed è improbabile che sia più lento ... – BillT

risposta

6

Mentre le altre risposte si concentrano a insistere che si prende l'approccio di sincronizzazione standard (cosa che condivido pienamente), ho pensato invece dovrei rispondere alla tua domanda per quanto riguarda Valgrind.

Per quanto ne so non ci sono problemi con Valgrind in esecuzione in ambiente multi-threaded. Credo che Valgrind imponga all'applicazione di funzionare su un singolo core, ma a parte questo non dovrebbe influenzare i thread.

Ciò che Valgrind sta probabilmente facendo alla tua applicazione sta modificando i tempi e le interazioni tra i tuoi thread in modi che potrebbero esporre bug e condizioni di gara nel tuo codice che normalmente non vedi mentre sei in esecuzione stand-alone.

La stessa logica è stato applicato per decidere che il bug non poteva essere nel quadro fonte filettatura aperto che si sta utilizzando vale anche per Valgrind a mio parere. Ti consiglio di considerare questi blocchi come bug nel tuo codice e di eseguirne il debug come tale, perché è molto probabile che siano.

Come nota a margine, utilizzando un mutex è probabilmente eccessivo per il problema che hai descritto. Dovresti invece indagare sui semafori o sulle variabili di condizione.

Buona fortuna.

+0

Non completamente convinto che ci siano errori nel mio codice, ma il tuo post è notato. Nota a margine - Ho esaminato le variabili di condizione utilizzando la libreria pthread e queste richiedono un mutex per arrestare le condizioni di gara sulla condizione stessa. – Taras

+1

@Taras: corretto sulla variabile di condizione. Semafori sarebbe la mia preferenza in questo caso. Molto più leggero di mutex. Nel problema dell'hang, perché non ispezionare il processo bloccato con gdb per scoprire cosa sta facendo? – Miguel

3

lettura/scrittura di un valore booleano non è un'operazione atomica su x86.

Vedi la mia domanda qui: Is volatile a proper way to make a single byte atomic in C/C++?

+0

La risposta afferma che per la maggior parte della scrittura un booleano è atomico: "Le CPU in genere leggono e scrivono singoli byte atomicamente". Dalle risposte alle domande il problema non è l'atomicità, è il momento in cui tutte le CPU vedono il nuovo valore. – Taras

2

Anche se la scrittura del booleana è un'operazione atomica, l'compiler and the CPU are free to re-order the update intorno altri accessi alla memoria. Il thread di attesa in attesa potrebbe essere risvegliato dal ciclo occupato e scoprire che la struttura di dati condivisa ha non in realtà stato ancora aggiornato.

Consiglio vivamente di attenersi alle primitive di threading disponibili per scrivere i programmi coerenti che vengono eseguiti esattamente come si desidera, ogni volta.

+0

L'unica cosa condivisa tra i due thread è il flag booleano (viene usato come segnale). Il thread di attesa occupato si attiva solo se il flag è stato impostato, il che significa che la modifica del flag deve essere propagata alla CPU che sta eseguendo il thread di attesa occupato. Detto questo, il codice come descritto non funzionerà ancora correttamente? – Taras

+0

Heh, hai ancora segnali _tried_? Questo potrebbe fare il trucco. :) – sarnold