2012-01-01 25 views
6

Necesito crear un bucle de juego del lado del servidor, el problema es cómo limitar el uso de la CPU de bucle.¿while loop siempre toma el uso completo de la CPU?

En mi experiencia de programación, un ciclo ocupado siempre toma el uso máximo de CPU que podría. Pero estoy leyendo el código de SDL (Simple DirectMedia Layer), tiene una función SDL_Delay(UINT32 ms), y tiene un ciclo while, ¿necesita el máximo uso de la CPU ?, si no es así, ¿por qué?

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)); 

Respuesta

3

Este código utiliza select para un tiempo de espera. select generalmente toma un descriptor de archivo y hace que la persona que llama espere hasta que ocurra un evento IO en la fd. También se necesita un argumento de tiempo de espera para el tiempo máximo de espera. Aquí el fd es 0, por lo que no ocurrirán eventos, y la función siempre regresará cuando se alcance el tiempo de espera.

El select(3) que se obtiene de la biblioteca C es una envoltura alrededor de la llamada select(2) sistema, lo que significa llamar select(3) finalmente se obtiene en el núcleo. Luego, el kernel no programa el proceso a menos que ocurra un evento IO o se alcance el tiempo de espera. Entonces el proceso no usa la CPU mientras espera.

Obviamente, el salto al kernel y la programación del proceso introducen retrasos. Por lo tanto, si debe tener una latencia muy baja (nanosegundos), debe esperar ocupado.

+2

Si un syscall 'select' recibe una señal, devuelve -1 con' errno == EINTR', por lo que no es cierto que 'select' siempre duerma el tiempo solicitado. –

+0

Bien, mi error. ¿Alguna idea de por qué el manual de GNU recomienda seleccionar sobre dormir en este caso? –

+0

Porque en algunos sistemas Unix antiguos (no Linux) 'sleep' se implementó con' SIGALRM' y 'pause' –

3

ese bucle no ocupará toda la CPU. Se utiliza una de las dos funciones diferentes para indicar al sistema operativo para hacer una pausa en el hilo de una determinada cantidad de tiempo y dejar que otro hilo utilizar 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

¿por qué? solo un 'while (1);' tomará el uso completo de la CPU, pero ¿por qué esto no –

+0

'nanosleep' y' select' (como se llama en la muestra) se bloqueará durante un período de tiempo determinado antes de volver. El ciclo while solo está ahí para manejar un caso especial donde la función de suspensión se interrumpe y regresa demasiado pronto. –

+0

¿Te refieres a hilo, pero solo qué hay de un solo hilo? –

1

Mientras que el hilo está bloqueado en SDL_Delay, cede la CPU a otras tareas. Si la demora es lo suficientemente larga, el sistema operativo incluso pondrá la CPU en modo inactivo o detenido si no hay otro trabajo que hacer. Tenga en cuenta que esto no funcionará bien si el tiempo de demora no es de al menos 20 milisegundos más o menos.

Sin embargo, esta no suele ser la forma correcta de hacer lo que sea que esté tratando de hacer. ¿Cuál es tu problema externo? ¿Por qué su bucle de juego nunca termina de hacer lo que sea necesario hacer en este momento y entonces necesita esperar a que suceda algo para que tenga más trabajo por hacer? ¿Cómo puede tener siempre una cantidad infinita de trabajo para hacer inmediatamente?