2008-11-05 29 views
13

En la programación embebido tradicional, vamos a dar una función de retardo de este modo:¿Hay alguna alternativa para dormir() en C?

for(i=0;i<255;i++) 
    for(j=0;j<255;j++); 

En opinión del microprocesador, es así como el sueño() función funciona?

¿Existe una alternativa para la función sleep() en C?

+0

ok en mi entorno es Windows Desktop Machine y compilador turbo c entonces para entorno de escritorio ¿hay alguna alternativa para sleep()? (no para sistemas integrados)) –

+0

¿Por qué necesitas una alternativa para dormir? Tradicionalmente, Sleep se implementará de una manera que no necesita hacer un ciclo ocupado como usted describe. En cambio, el hilo simplemente no sería programado. –

Respuesta

11

Las alternativas dependen de lo que intente hacer y del sistema operativo en el que se encuentre.

Si lo que desea es perder el tiempo, entonces estos pueden ayudar:

En la mayoría de los sistemas de tipo Unix encontrará una función de 'usleep', que es más o menos como el sueño con mayor resolución. Tenga cuidado con eso porque generalmente no puede dormir por solo un microsegundo.

En algunos sistemas de tipo unix, la llamada al sistema de selección se puede utilizar con todos los conjuntos de descriptores de archivo cero para obtener una espera de segundos por segundo bastante precisa.

En los sistemas de Windows, tiene el modo de suspensión, que es más o menos el mismo, pero tarda unos milisegundos.

En un sistema operativo multitarea, a veces se puede asignar a 0 una función de reposo como parámetro. Por lo general, esto hace que la función abandone su intervalo de tiempo, pero se volverá a programar inmediatamente si ninguna otra tarea está lista para ejecutarse.

24

El tipo de bucle que describe se denomina "espera ocupada". En sistemas operativos reales, dormir no causa una espera ocupada; le dice al sistema operativo que no programe el proceso hasta que termine el período de espera.

+0

ok cualquier alternativa para dormir()? –

+0

hay un lugar para ambos. Por ejemplo, kernel de Windows KeStallExecutionProcessor está ocupado espera y KeDelayExecutionThread no está ocupado espere. Hay una situación en la que desea esperar sin perder el contexto, por ejemplo, reiniciar hw -> esperar algunos micro -> hacer resto de hw init – Ilya

+0

Acepto que hay casos en los que la espera ocupada es de hecho apropiada y se implementa en kernel. por ejemplo, bloqueo de giro. Así que supongo que mi respuesta debería ser: "en sistemas operativos reales, dormir no suele causar una espera ocupada". :-) –

7

Habla de "programación integrada" en el OP. Si está realizando un trabajo incrustado y necesita algo como sleep(), a menudo hay contadores de hardware/temporizadores disponibles. Esto variará de arquitectura a arquitectura, así que eche un vistazo a la hoja de datos.

Si usted no está haciendo el trabajo incorporado, me disculpo :)

6

Si está utilizando para bucles, es mejor que sepas lo que compilan y cuánto tiempo a esas instrucciones toman a su velocidad de reloj dada , y asegurar la CPU ejecuta sus instrucciones y nada más (esto se puede hacer en sistemas embebidos, pero es complicado, ya que no permite interrupciones).

De lo contrario, usted no será capaz de decir el tiempo que realmente va a tomar.

juegos de PC tempranos tenían este problema - que fueron construidas para un PC 4.7MHz y, cuando los ordenadores más rápidos llegó, estaban injugable.

La mejor manera de que un 'sueño' pueda funcionar es que la CPU sepa qué hora es en un punto determinado. No necesariamente el tiempo real (7:15 a.m.), pero al menos el tiempo relativo (8612 segundos desde algún punto en el tiempo).

De esta forma puede aplicar un delta a la hora actual y esperar en un bucle hasta alcanzar el + delta actual.

Cualquier cosa que se basa en ciclos número de CPU es inherentemente poco fiables como la CPU puede irse a otra tarea y dejar su colgante de lazo.

Digamos que usted tiene un 16-bit de memoria mapeada puerto E/S, que los incrementos de la CPU una vez por segundo. Supongamos también que está en la ubicación de memoria 0x33 en su sistema integrado, donde las entradas también son de 16 bits. Una función llamada del sueño entonces se convierte en algo así como:

void sleep (unsigned int delay) { 
    unsigned int target = peek(0x33) + delay; 
    while (peek(0x33) != target); 
} 

Vas a tener que asegurarse de que peek() devuelve el contenido de la memoria cada vez que (por lo que la optimización de compiladores no arruinar definitivamente la lógica) y que sus carreras while más de una vez por segundo para que no se pierda el objetivo, pero estos son problemas operacionales que no afectan el concepto que presento.

+2

Supongo que le gustaría 'while (peek (0x33) erikkallen

20

Un mecanismo común es utilizar un select() que se garantiza que el tiempo de espera, y especificar el tiempo de sueño como el tiempo de espera:

// Sleep for 1.5 sec 
struct timeval tv; 
tv.tv_sec = 1; 
tv.tv_usec = 500000; 
select(0, NULL, NULL, NULL, &tv); 

El select() se suele utilizar para comprobar un conjunto de descriptores de archivos y esperar hasta al menos uno está listo para realizar E/S. Si ninguno está listo (o, en este caso, si no se especifica ningún fds), se agotará el tiempo de espera.

La ventaja de select() en un bucle ocupado es que consume muy pocos recursos mientras duerme, mientras que un bucle ocupado monopoliza el procesador tanto como lo permite su nivel de prioridad.

+1

Probablemente sobre-ingeniería, pero pensé que select() era interrumpible por señales. ¿Qué sucede si se interrumpe después de 1/2 segundo? – paxdiablo

+0

Buena captura: en ese caso, use pselect() para enmascarar señales, o cree sus propios manejadores de señal conscientes del sueño. ¡Gracias! –

+0

Pero está escrito [aquí] (http://www.gnu.org/software/libc/manual/html_node/Sleeping.html) _ (allí hace clic en esperar IO) _ que 'select' no es interrumpible. El problema con select se explica [aquí] (http://stackoverflow.com/questions/9774986/linux-select-vs-ppoll-vs-pselect) –

1

En un sistema operativo derivado de Unix, probablemente programe una llamada a la señal(), y su código simplemente bloqueará el código hasta que se eleve la señal. Las señales están diseñadas para este propósito, y son muy simples y eficientes.

+0

Las señales no están destinadas para retrasos en general, aunque se pueden usar para eso. No son el mecanismo de gastos más bajos, ya que están configurados para la interrupción asincrónica. La alternativa select() descrita anteriormente es probablemente más eficiente. – bog

5

Busy-waiting es para aficionados incluso en un sistema integrado, utilice una fuente en tiempo real.

6

Hay más información sobre cómo el sueño() funciona here

Por cierto, ocupado en espera no es necesariamente para los aficionados - a pesar de que se quema procesador que es posible que desee utilizar para otros fines. Si está utilizando una fuente de tiempo, está limitado a la granularidad de esa fuente. P.EJ. si tiene un temporizador de 1 ms y quiere recorrer 500 uS, tiene un problema. Si su sistema integrado puede manejar el hecho de que estará zumbando en un bucle para 500 uSec, eso podría ser aceptable. E incluso si tiene un temporizador con la granularidad deseada, también necesita obtener una interrupción de ese temporizador en el momento correcto ... luego envíe el controlador de interrupción ... luego obtenga su código. A veces, un bucle ocupado es la solución más conveniente. A veces.

3

sleep en realidad interactúa con el sistema operativo, donde los procesos inactivos se colocan fuera de la cola de programación. Suelo usar:

poll(0, 0, milliseconds); 

para sistemas que cumplen con POSIX. select también funciona para Windows (deben tener una API nativa (probablemente llamada Sleep) para eso.)

+2

Encontramos un error en linux 2.6.11.6 que causaba que la encuesta colgara todo el sistema bajo ciertas situaciones. Cambiar a select() solucionó el problema; no sé si todavía existe en kernels recientes. –

4

cualquier compilador C decente, sin trabajo adicional, retire completamente su código y el retraso se desvanecería

+4

Recuerdo algunos puntos de referencia de hace muchos años en los que un ejecutable específico generado por el compilador superaba a otros compiladores en muchos órdenes de magnitud. Resultó ser el compilador al darse cuenta de que el resultado del bucle no se usaba en ningún otro lado, por lo que optimizó la extinción del ciclo completo :-). – paxdiablo

8

Usted haría no use el código que publicó para dormir en un sistema integrado. Un compilador decente lo eliminaría por completo, e incluso si su compilador no lo elimina, no es óptimo, ya que ejecutar el procesador en un ciclo cerrado quemará energía, lo cual es un problema para el sistema integrado. Incluso los sistemas que no funcionan con batería se preocupan por el uso de energía, ya que un menor consumo de energía significa un suministro de energía y refrigeración más económicos.

La forma en que normalmente lo hace es que su CPU implementará algún tipo de instrucciones IDLE o SLEEP, que provocarán que deje de procesar temporalmente los comandos. Una línea de interrupción externa conectada a un circuito de temporizador reactivará el procesador a intervalos regulares, y en ese punto la CPU verifica si ha estado dormido el tiempo suficiente y, si no, vuelve a dormirse.

//Pseudo code 
int start = getTime(); 
int end = start + sleepTime; 

while (getTime() < end) { 
     asm("SLEEP"); 
} 

Los detalles exactos varían de procesador a procesador. Si se está ejecutando como un proceso en un SO, la llamada de espera generalmente solo le dice al planificador que suspenda su proceso, y luego el núcleo decide si programar otro proceso o dormir la CPU. Además, el código anterior no será adecuado para sistemas en tiempo real, que quieran garantías de fecha límite, etc. En esos casos, necesitará obtener el tiempo en el ciclo, saber la duración de la interrupción del tiempo para saber si puede dormir sin volando la fecha límite, y posiblemente reprogramar el hardware del temporizador o la espera ocupada.

+0

¿Qué sucede si el final bk1e

+0

pseudocódigo, tengo que ignorar esos detalles, asumir un tamaño infinito int ;-) –

2

La página 20 de 'Enhebrado en C#' de Joseph Albahari tiene una interesante discusión al respecto. No puede dormir por menos de 1 ms en .Net pero DateTime.Ticks tiene una granularidad de intervalos de 100 nanosegundos (= 0.1 microsegundos). Para controlar mi stepper CNC de 5 ejes, solo necesito hacer una pausa de 10 microsegundos entre los comandos de paso. He usado un microcontrolador para hacer el bucle desagradable, pero creo que está bien entregar un procesador para el trabajo si tienes un grupo completo de todos modos, detén el hilo cuando puedas. Al menos no será siempre el mismo.

0

un intento ... Para resolver este problema realmente, es decir, algo que funciona (no como los intentos anteriores de respuesta) lol

todavía tengo que mejorar este código para hacerlo salir. Pocos complementos son bienvenidos.

// Sleep for both Windows and Linux: 
// Too bad? No one proposed you a solution that works? 
// Since Windows has no select.h nor poll.h, an implementation 
// is necessary. 
// 
// Solutions on boards are often refered to use either select or poll, but ok, what about C (not c++)? 
// 
/// implementation of poll is destined in this attempt for windows 
/// Ideally, you add this part of code to the header of you *.c file, and it might work through... 

#ifdef WIN32 
#include <time.h> 
#include <sys/time.h> 
#include <ws2tcpip.h> 
#include <Winsock2.h> 
#include <windows.h> 
/* winsock doesn't feature poll(), so there is a version implemented 
* in terms of select() in mingw.c. The following definitions 
* are copied from linux man pages. A poll() macro is defined to 
* call the version in mingw.c. 
*/ 
#define POLLIN  0x0001 /* There is data to read */ 
#define POLLPRI  0x0002 /* There is urgent data to read */ 
#define POLLOUT  0x0004 /* Writing now will not block */ 
#define POLLERR  0x0008 /* Error condition */ 
#define POLLHUP  0x0010 /* Hung up */ 
#define POLLNVAL 0x0020 /* Invalid request: fd not open */ 
struct pollfd { 
    SOCKET fd;  /* file descriptor */ 
    short events;  /* requested events */ 
    short revents; /* returned events */ 
}; 

int mingw_poll (struct pollfd *, unsigned int, int); 

#define poll(x, y, z)  mingw_poll(x, y, z) 
#endif 





int mingw_poll(struct pollfd *fds, unsigned int nfds, int timo) 
{ 
    struct timeval timeout, *toptr; 
    fd_set ifds, ofds, efds, *ip, *op; 
    int i, rc; 

    /* Set up the file-descriptor sets in ifds, ofds and efds. */ 
    FD_ZERO(&ifds); 
    FD_ZERO(&ofds); 
    FD_ZERO(&efds); 
    for (i = 0, op = ip = 0; i < nfds; ++i) { 
    fds[i].revents = 0; 
    if(fds[i].events & (POLLIN|POLLPRI)) { 
     ip = &ifds; 
     FD_SET(fds[i].fd, ip); 
    } 
    if(fds[i].events & POLLOUT) { 
     op = &ofds; 
     FD_SET(fds[i].fd, op); 
    } 
    FD_SET(fds[i].fd, &efds); 
    } 

    /* Set up the timeval structure for the timeout parameter */ 
    if(timo < 0) { 
    toptr = 0; 
    } else { 
    toptr = &timeout; 
    timeout.tv_sec = timo/1000; 
    timeout.tv_usec = (timo - timeout.tv_sec * 1000) * 1000; 
    } 

#ifdef DEBUG_POLL 
    printf("Entering select() sec=%ld usec=%ld ip=%lx op=%lx\n", 
      (long)timeout.tv_sec, (long)timeout.tv_usec, (long)ip, (long)op); 
#endif 
    rc = select(0, ip, op, &efds, toptr); 
#ifdef DEBUG_POLL 
    printf("Exiting select rc=%d\n", rc); 
#endif 

    if(rc <= 0) 
    return rc; 

    if(rc > 0) { 
     for (i = 0; i < nfds; ++i) { 
      int fd = fds[i].fd; 
     if(fds[i].events & (POLLIN|POLLPRI) && FD_ISSET(fd, &ifds)) 
      fds[i].revents |= POLLIN; 
     if(fds[i].events & POLLOUT && FD_ISSET(fd, &ofds)) 
      fds[i].revents |= POLLOUT; 
     if(FD_ISSET(fd, &efds)) 
      /* Some error was detected ... should be some way to know. */ 
      fds[i].revents |= POLLHUP; 
#ifdef DEBUG_POLL 
     printf("%d %d %d revent = %x\n", 
       FD_ISSET(fd, &ifds), FD_ISSET(fd, &ofds), FD_ISSET(fd, &efds), 
       fds[i].revents 
     ); 
#endif 
     } 
    } 
    return rc; 
} 
+0

Creo que esta respuesta está fuera de la pista de la pregunta original. Esto se parece más a una solución multiplataforma para seleccionar() e involucra encuestas. Una verdadera suspensión del sistema operativo no hace que el proceso sondee. –

1
#include <Windows.h> 

static NTSTATUS(__stdcall *NtDelayExecution)(BOOL Alertable, PLARGE_INTEGER DelayInterval) = (NTSTATUS(__stdcall*)(BOOL, PLARGE_INTEGER)) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtDelayExecution"); 

static NTSTATUS(__stdcall *ZwSetTimerResolution)(IN ULONG RequestedResolution, IN BOOLEAN Set, OUT PULONG ActualResolution) = (NTSTATUS(__stdcall*)(ULONG, BOOLEAN, PULONG)) GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwSetTimerResolution"); 




static void SleepShort(float milliseconds) { 
    static bool once = true; 
    if (once) { 
     ULONG actualResolution; 
     ZwSetTimerResolution(1, true, &actualResolution); 
     once = false; 
    } 

    LARGE_INTEGER interval; 
    interval.QuadPart = -1 * (int)(milliseconds * 10000.0f); 
    NtDelayExecution(false, &interval); 
} 

Sí se utiliza algunas funciones del núcleo indocumentados, pero honestamente, es mucho más rápido que la mayoría de las sugerencias y obras muy bien, (tenga en cuenta que se limitará a la cantidad de la CPU, por ejemplo, la mina solo puede dormir 500 nanosegundos (0.5))

1

disponible en linux usleep (int mic Roseconds) nanosleep (...) más precisión ver páginas man para los argumentos de llamada

Cuestiones relacionadas