2012-12-03 19 views
18

Da quello che ho capito, scrivi il tuo demone Linux che ascolta una richiesta in un ciclo infinito.
Qualcosa di simile ..Il ciclo While infinito occupa risorse della CPU?

int main() { 
    while(1) { 
     //do something... 
    } 
} 

ref: http://www.thegeekstuff.com/2012/02/c-daemon-process/

ho letto che dormire un programma lo fa andare in modalità di attesa in modo che non mangia le risorse.

1.Se si desidera che il mio daemon controlli una richiesta ogni 1 secondo, le risorse seguenti sarebbero consumate dalle risorse?

int main() { 
    while(1) { 
     if (request) { 
      //do something... 
     } 
     sleep(1) 
    } 
} 

2. Se dovessi togliere il sonno, cosa significa il consumo della CPU salirà al 100%?

3.È possibile eseguire un ciclo infinito senza mangiare risorse? Dire ... se non fa nulla, ma si limita a se stesso. O semplicemente dormi (1).

I loop infiniti e le risorse della CPU sono un mistero per me.

+1

Sleeping indica allo scheduler di eseguire sulla CPU un altro processo anziché il processo per uno smontaggio specifico del tempo (anche per mantenerlo semplice). Il tuo programma non consumerà risorse della CPU durante il sonno. Anche dormire per pochi millisecondi rende le cose fluide in un ciclo infinito come lo hai mostrato. –

+3

Se stai ascoltando *, allora dovresti usare qualche syscall di multiplexing come 'poll (2)' (o il più vecchio, quasi obsoleto, 'select (2)') –

risposta

12

È possibile eseguire un ciclo infinito senza mangiare risorse? Dire ... se non fa nulla, ma si limita a se stesso. O semplicemente dormi (1).

C'è una soluzione migliore.
È possibile utilizzare solo un semaforo , che rimane bloccato all'inizio del ciclo e si può segnalare il semaforo ogni volta che si desidera eseguire il ciclo.
Si noti che questo non mangerà alcuna risorsa.

+1

"non mangerà nessuna risorsa" non è esattamente vero .. La creazione di un semaforo utilizza risorse e oggetti del kernel ed è un'operazione abbastanza pesante. L'attesa sul semaforo è un'operazione in modalità kernel e incorre in un cambio di contesto anche in modalità kernel. –

+0

Un semaforo sarebbe appropriato se si utilizza un timeout, ma il sonno è probabilmente il migliore. Il semaforo è più rilevante se vuoi che il tuo codice si attivi * o * timeout * o * qualche evento esterno. –

+0

Grazie per aver menzionato il semaforo. Devo esplorare questo quando arriverà il tempo :) – resting

2

La risposta breve è sì - la rimozione del sonno fornisce CPU al 100% - ma la risposta dipende da alcuni dettagli aggiuntivi. Consuma tutta la CPU che può ottenere, a meno che ...

  1. Il corpo del loop è banale e ottimizzato.
  2. Il ciclo contiene un'operazione di blocco (come un'operazione di file o di rete). Il link che fornisci suggerisce di evitare questo, ma spesso è una buona idea bloccare fino a quando accade qualcosa di rilevante.

EDIT: per lo scenario, sostengo la proposta fatta da @Als.

EDIT 2: Mi aspetto che questa risposta abbia ricevuto un -1 perché ritengo che le operazioni di blocco possano essere effettivamente una buona idea. [Se hai -1, dovresti lasciare una motivazione in un commento in modo che tutti possano imparare qualcosa.]

L'attuale pensiero popolare è che l'IO non blocco (basato su eventi) è buono e il blocco è negativo. Questa visione è semplificata perché presuppone che tutto il software che esegue l'IO possa migliorare il throughput utilizzando operazioni non bloccanti.

Cosa? Sto davvero suggerendo che l'utilizzo dell'IO non bloccante può effettivamente ridurre il throughput? Sì, può. Quando un processo serve una singola attività, è meglio usare l'IO di blocco perché il blocco dell'IO brucia solo risorse che sono già state pagate nell'esistenza del processo.

Al contrario, l'IO non bloccante può comportare un sovraccarico fisso maggiore rispetto al semplice IO di blocco. Se il processo non è in grado di fornire IO aggiuntivi che possono essere intercalati, non viene ottenuto nulla pagando per l'installazione non bloccante. (In pratica, il costo maggiore di IO non bloccante non appropriato è semplicemente nella complessità del codice aggiunto. Oltre a questo, questo argomento è in gran parte un esercizio di pensiero.)

Sotto IO di blocco ci affidiamo al sistema operativo per pianificare quei processi che può fare progressi. Questo è ciò che il sistema operativo è progettato per fare.

Sotto IO non bloccanti abbiamo maggiori costi di installazione ma possiamo condividere le risorse del processo e le sue discussioni tra lavoro interlacciato. L'IO non bloccante è quindi ideale per qualsiasi processo che serve più attività indipendenti, come un server web. Il throughput ottenuto è di gran lunga superiore al costo fisso dei costi di I/O non bloccanti.

+0

Il software potrebbe non migliorare il throughput utilizzando l'I/O non bloccante, ma migliora sempre * la reattività *. Sì, dovresti bloccare, ma dovrebbe essere una chiamata di blocco che attende una serie di eventi, non una chiamata I/O di blocco che fa sì che gli input dell'utente vengano ignorati fino al completamento dell'I/O. 'select',' poll', 'aio_suspend' sono tutti esempi. Dici "Se il processo non è in grado di fornire IO aggiuntivi che possono essere interlacciati", ma c'è sempre almeno un input aggiuntivo di quello che può accadere ... una richiesta utente di uscire. –

+0

@BenVoigt Questo è vero. Le applicazioni interattive non dovrebbero bloccare indefinitamente, ad es. un semaforo dovrebbe quindi utilizzare un timeout. Detto questo, i servizi di back-end posix possono ricevere segnali anche quando si esegue un'operazione di blocco. Tutto sommato, hai sollevato un buon punto da ricordare - grazie. –

13

Le chiamate poll e select (menzionate da Basile Starynkevitch in un commento) o un semaforo (menzionato da Als in una risposta) sono i modi corretti per attendere le richieste, a seconda delle circostanze. Su sistemi operativi senza poll o select, dovrebbe esserci qualcosa di simile.

sleep, YieldProcessor, né sched_yield sono modi adeguati per eseguire questa operazione, per i seguenti motivi.

YieldProcessor e sched_yield spostare semplicemente il processo fino alla fine della coda eseguibile ma lasciarlo eseguibile. L'effetto è che consentono l'esecuzione di altri processi con priorità uguale o superiore, ma, quando tali processi vengono eseguiti (o se non ce ne sono), il processo che ha chiamato YieldProcessor o sched_yield continua a essere eseguito. Questo causa due problemi. Uno è che i processi con priorità più bassa non verranno ancora eseguiti. Un altro è che questo fa sì che il processore sia sempre in esecuzione, usando energia. Preferiremmo che il sistema operativo riconosca quando nessun processo deve essere in esecuzione e per mettere il processore in uno stato di bassa potenza.

sleep potrebbe consentire questo stato di bassa potenza, ma svolge un gioco di ipotesi su quanto tempo sarà fino a quando la richiesta successiva arriva, si sveglia il processore più volte quando non ce n'è bisogno, e rende il processo meno reattivo alle richieste, dal momento che il processo continuerà a dormire fino alla scadenza del tempo richiesto anche se c'è una richiesta di assistenza.

Le chiamate poll e select sono progettate esattamente per questa situazione. Dicono al sistema operativo che questo processo vuole servire una richiesta che arriva su uno dei suoi canali di I/O, ma altrimenti non ha lavoro da fare. Ciò consente al sistema operativo di contrassegnare il processo come non eseguibile e di mettere il processore in uno stato di bassa potenza se adatto.

L'utilizzo di un semaforo fornisce lo stesso comportamento, con la differenza che il segnale per riattivare il processo proviene da un altro processo che solleva il semaforo anziché dall'attività che si verifica in un canale I/O. I semafori sono adatti quando il segnale per fare un po 'di lavoro arriva in questo modo; usa semplicemente quello di poll o un semaforo è più appropriato per la tua situazione.

La critica a poll, select o un semaforo causa una chiamata in modalità kernel irrilevante, poiché gli altri metodi provocano anche chiamate in modalità kernel. Un processo non può dormire da solo; deve chiamare il sistema operativo per richiederlo. Allo stesso modo, YieldProcessor e sched_yield eseguono richieste al sistema operativo.