2012-01-01 14 views
6

Ho bisogno di creare un loop di gioco lato server, il problema è come limitare l'utilizzo della CPU in loop.fa il ciclo mentre prende sempre l'uso completo della CPU?

Nella mia esperienza di programmazione, un ciclo occupato utilizza sempre il massimo utilizzo della CPU. Ma sto leggendo il codice di SDL (Simple DirectMedia Layer), ha una funzione SDL_Delay(UINT32 ms), e ha un ciclo while, ci vuole massimo utilizzo della CPU, se no, perché?

https://github.com/eddieringle/SDL/blob/master/src/timer/unix/SDL_systimer.c#L137-158

do { 
    errno = 0; 

#if HAVE_NANOSLEEP 
    tv.tv_sec = elapsed.tv_sec; 
    tv.tv_nsec = elapsed.tv_nsec; 
    was_error = nanosleep(&tv, &elapsed); 
#else 
    /* Calculate the time interval left (in case of interrupt) */ 
    now = SDL_GetTicks(); 
    elapsed = (now - then); 
    then = now; 
    if (elapsed >= ms) { 
     break; 
    } 
    ms -= elapsed; 
    tv.tv_sec = ms/1000; 
    tv.tv_usec = (ms % 1000) * 1000; 

    was_error = select(0, NULL, NULL, NULL, &tv); 
#endif /* HAVE_NANOSLEEP */ 
} while (was_error && (errno == EINTR)); 

risposta

3

Questo codice utilizza select un timeout. select di solito prende un descrittore di file e fa in modo che il chiamante attenda fino a quando si verifica un evento IO sul file fd. Richiede anche un argomento di timeout per il tempo massimo di attesa. Qui il file fd è 0, quindi non si verificheranno eventi e la funzione ritornerà sempre al raggiungimento del timeout.

Il select(3) che si ottiene dalla libreria C è un wrapper per la chiamata di sistema select(2), il che significa chiamando select(3) alla fine si ottiene nel kernel. Il kernel quindi non pianifica il processo a meno che non si verifichi un evento IO o il timeout sia raggiunto. Quindi il processo non sta utilizzando la CPU durante l'attesa.

Ovviamente, il salto nel kernel e la pianificazione del processo introducono ritardi. Quindi, se devi avere una latenza molto bassa (nanosecondi), dovresti usare l'attesa attenta.

+2

Se un syscall 'select' riceve un segnale, restituisce -1 con' errno == EINTR' quindi non è vero che 'select' sempre dorme il tempo richiesto. –

+0

OK, mio ​​errore. Qualche idea sul perché il manuale GNU raccomanda di selezionare su sleep in questo caso? –

+0

Perché su alcuni vecchi sistemi Unix (non Linux) 'sleep' è stato implementato con' SIGALRM' e 'pause' –

3

Questo circuito non prendere tutto CPU. Esso utilizza una di due diverse funzioni di dire al sistema operativo per sospendere il filo per una data quantità di tempo e lasciando un altro thread utilizzare la CPU:

// First function call - if HAVE_NANOSLEEP is defined. 
was_error = nanosleep(&tv, &elapsed); 

// Second function call - fallback without nanosleep. 
was_error = select(0, NULL, NULL, NULL, &tv); 
+0

perché? solo un 'while (1);' ci vorrà un uso completo della CPU, ma perché questo non è –

+0

'nanosleep' e' select' (come nel tuo esempio) bloccherà per un dato periodo di tempo prima di tornare. Il ciclo while è presente solo per gestire un caso speciale in cui la funzione sleep viene interrotta e ritorna troppo presto. –

+0

Vuoi dire thread, ma solo per quanto riguarda un solo thread? –

1

Mentre il thread è bloccato in SDL_Delay, restituisce la CPU ad altre attività. Se il ritardo è abbastanza lungo, il sistema operativo metterà anche la CPU in modalità inattiva o ferma se non c'è altro lavoro da fare. Si noti che questo non funzionerà bene se il tempo di ritardo non è di almeno 20 millisecondi o giù di lì.

Tuttavia, questo di solito non è il modo giusto per fare tutto ciò che si sta tentando di fare. Qual è il tuo problema esterno? Perché il tuo ciclo di gioco non finisce mai di fare tutto ciò che deve essere fatto in questo momento e quindi devi aspettare che succeda qualcosa in modo che abbia più lavoro da fare? Come può sempre avere una quantità infinita di lavoro da fare immediatamente?

Problemi correlati