2013-11-02 9 views
5

Sto scrivendo un programma di comunicazione di rete usando socket non bloccanti (C/C++) e select. Il programma è abbastanza grande, quindi non posso caricare il codice sorgente. In una sessione di test molto aggressiva, utilizzo il codice di test per aprire e chiudere frequentemente sia TCP che UDP. Finisce sempre che quell'estremità non risponde e ha un utilizzo della CPU superiore al 98 o 99%. Quindi utilizzo gdb da allegare. "bt" mostra quanto segue:Qual è il problema di select() che utilizza tanta potenza della CPU?

0x00007f1b71b59ac3 in __select_nocancel() at ../sysdeps/unix/syscall-template.S:82 
82 ../sysdeps/unix/syscall-template.S: No such file or directory. 
    in ../sysdeps/unix/syscall-template.S 

Che tipo di errore potrebbe essere?

$ uname -a 
Linux kiosk2 2.6.32-34-generiC#77-Ubuntu SMP Tue Sep 13 19:39:17 UTC 2011 x86_64 GNU/Linux 
+0

Quindi, qual era il problema? – Tshepang

risposta

26

E 'impossibile dire senza guardare il codice, ma spesso quando un ciclo di selezione basata inizia a girare a utilizzo della CPU ~ 100%, è perché una o più delle prese ti ha detto select() da guardare sono già pronto for-read (e/o ready-for-write) in modo che select() ritorni subito invece di bloccare ... ma poi il codice trascura effettivamente lo recv() (o send()) qualsiasi dato su quel socket. Dopo aver fallito nel leggere/scrivere qualcosa, il ciclo degli eventi tenterebbe di tornare a dormire chiamando di nuovo select(), ma ovviamente i dati del socket (o lo spazio del buffer, nel caso pronto per la scrittura) è ancora lì in attesa di essere gestito , così select() ritorna subito ancora una volta, il codice buggy trascura di fare la lettura (o write()) di nuovo, e intorno e intorno andiamo a tutta velocità :)

Un'altra possibilità potrebbe essere che si sta passando a un valore di timeout per select() ovvero zero o quasi zero, che causa il ritorno immediato di select() anche quando nessun socket è pronto per niente ... ciò accade spesso quando le persone dimenticano di reinizializzare la struttura temporale prima di ogni chiamata a select(). È necessario reinizializzare la struttura temporale ogni volta poiché alcune implementazioni di select() lo modificano prima di tornare.

Il mio suggerimento è quello di mettere alcuni printf (o il vostro equivalente preferito) immediatamente prima e immediatamente dopo la vostra chiamata a select(), e guardare quell'uscita mentre riproducete l'errore. Questo ti mostrerà se lo spinning sta accadendo all'interno di una singola chiamata a select(), o se qualcosa sta causando select() di tornare immediatamente più e più volte.

+3

+1 una delle migliori risposte su SO che ho visto quando non c'è codice sorgente nella domanda –

Problemi correlati