Newsgroup: it.comp.lang.c
Titolo: Load molto alto a causa di un ciclo while

Ciao a tutti!
Ho questo problema: un mio programma deve avere un ciclo while durante il
quale vengono presi dati da un Socket e, se recv ritorna qualcosa,
processarli.
In caso contrario, semplicemente il ciclo continua.
Io ho scritto questo:
  while(!hasToStop)
  {
    usleep(50);
    if((res = recv(sockv6, bufsock, sizeof(bufsock), 0)) < 0)
    {
      if(res != -1) // Nonblocking Socket. If no data read, recv will
return -1
        logger(LOG_NOTICE, "6to4", "socket error");
      continue;
    }
    ...
  }
Il socket e' impostato come nonblocking, quindi devo fare il controllo.
Il problema e' che il load della macchina schizza alle stelle.
Per cercare di ridurlo ho introdotto una pausa (usleep), ma questo mi
compromette parecchio le prestazioni.
Qualcuno ha un'idea di come possa risolvere il problema (nessuna pausa in
mezzo, ma load ridotto se non ci sono dati dal socket)?
Grazie
Luca Bertoncello
(
luca...@lucabert.de
)
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 non ci sono dati dal socket)?
La soluzione che ho adottato io in un caso analogo
probabilmente non sarà l'ideale, comunque...
In sostanza ho adottato uno sleep di durata variabile. Se
arrivano dati per un certo numero di cicli lo sleep viene
ridotto al minimo e quando per un certo numero di cicli
non ne arrivano più, viene aumentato. In pratica c'è un
tempo di ritardo nella risposta del sistema ma per le mie
necessità il guadagno è stato di gran lunga più
vantaggioso. Questo schema si può raffinare di molto con
strategie euristiche dipendenti dal problema, se mai il
problema lo permette.
Naturalmente se hai un flusso di dati elevato e costante
il tutto non serve a niente o a poco.
Con ogni probabilità il mio workaround rivela bene che io
non amo molto scendere oltre le funzioni di base, fino a
eventuali caratteristiche vantaggiose del sistema
operativo, per me la portabilità è sempre stata la prima
caratteristica desiderabile.
ciao!
Apx.
-- 
"La teoria è sapere come funzionano le cose e
non sapere come farle funzionare; la pratica è
sapere come far funzionare la cose senza sapere come
funzionano; il nostro scopo è unire la pratica
alla teoria per riuscire a non far funzionare
le cose senza capire come abbiamo fatto"


man select
Ciao!

 man select
Decisamente no...
Innanzitutto, nel Thread ho solo UN socket.
In secondo luogo non mi risolve il problema, direi...
Con select posso sapere se ho dei dati da leggere, ma alla fine devo
sempre mettere una qualche pausa nel programma, per evitare di far
schizzare il Load alle stelle.
Oppure ho capito completamente sbagliato?


 
La select (e simili) mette in wait il programma finché "almeno uno" dei file descriptors non cambia stato. Il fatto che te ne abbia uno solo è una semplificazione.
Ciao!

FtM ha scritto:


Aha! Capito!
Una domanda ancora: e' pero' possibile, per me, terminare questa select in
modo da far uscire il programma? Oppure devo aspettare il timeout?


 
Esce con evento su un qualsiasi fd, con timeout o con un interrupt (in qual caso la select "dovrebbe" tornare -1 con errno settato a EINTR): quindi o metti un fd di controllo, o un timeout accettabile o generi/aspetti un'interruzione - la scelta migliore dipende da cosa devi fare!
Ciao!
P.S. Occhio che se segui il flow del tuo programma con un debugger la select() potrebbe interrompersi appunto per questo comportamento..


Ho letto questa solo ora.. La select() è apparsa fin dal 4.2BSD, quindi ha la stessa compatibilità di connect() o listen(). L'approccio con i ritardi è sicuramente fantasioso, ma di sicuro il design dell'architettura a socket ha sempre messo a disposizione soluzioni migliori a livello di sistema!
Ciao!

 disposizione soluzioni migliori a livello di sistema!
ahahah mannaggia la mia pigrizia a leggere la
documentazione, ma LOL. Sarà per il prossimo progetto :D


 Esce con evento su un qualsiasi fd, con timeout o con un interrupt (in qual
caso la select "dovrebbe" tornare -1 con errno settato a EINTR): quindi o
metti un fd di controllo, o un timeout accettabile o generi/aspetti
un'interruzione - la scelta migliore dipende da cosa devi fare!
OK, ho scritto un piccolo programma di test che attiva due thread, ognuno
dei quali ascolta su una porta.
Due PIPEs mi consentono di terminare i Thread alla semplice pressione di
un tasto.
Direi che e' la strada giusta! Stasera o domani provo ad integrarlo nel
programma.
Ciao e grazie


 Esce con evento su un qualsiasi fd, con timeout o con un interrupt (in qual
caso la select "dovrebbe" tornare -1 con errno settato a EINTR): quindi o
metti un fd di controllo, o un timeout accettabile o generi/aspetti
un'interruzione - la scelta migliore dipende da cosa devi fare!
OK, ce l'ho fatta!
Ho due socket e due pipes. Nei due thread vengono controllati, tramite
select, un socket e una pipe.
Per terminare il socket mando un carattere alla pipe che mi interrompe il
ciclo.
Il load e' minimo e la velocita' e' quasi doppia...
OTTIMO consiglio, grazie!
Ciao


 
Figurati ;) Comunque visto che ti interessa la programmazione di rete su *nix, non posso non linkarti il famosissimo "Beej's Guide to Network Programming" 
http://beej.us/guide/bgnet/
 - parte da un livello base e copre tutte le situazioni più comuni con svariati esempi :-)
Ciao!