¿Existe una función de suspensión alternativa en C a milisegundos?

133

Tengo un código fuente que se compiló en Windows. Lo estoy convirtiendo para que se ejecute en Red Hat Linux.

El código fuente ha incluido el <windows.h>archivo de encabezado y el programador ha utilizado la Sleep()función para esperar un período de milisegundos. Esto no funcionará en Linux.

Sin embargo, puedo usar la sleep(seconds)función, pero eso usa un número entero en segundos. No quiero convertir milisegundos a segundos. ¿Existe una función de suspensión alternativa que pueda usar con la compilación de gcc en Linux?

ant2009
fuente
sleep(/*seconds*/)en <unistd.h>trabajos, pero si uso con printf("some things")sin \n, no funciona.
EsmaeelE
Para usar en este caso, debemos enjuagar la salida fflush(stdout);después de cada unoprintf()
EsmaeelE

Respuestas:

179

Sí, se han definido estándares POSIX anteriores usleep(), por lo que está disponible en Linux:

   int usleep(useconds_t usec);

DESCRIPCIÓN

La función usleep () suspende la ejecución del hilo de llamada para (al menos) usec microsegundos. El sueño puede alargarse ligeramente por cualquier actividad del sistema o por el tiempo dedicado a procesar la llamada o por la granularidad de los temporizadores del sistema.

usleep()toma microsegundos , por lo que deberá multiplicar la entrada por 1000 para dormir en milisegundos.


usleep()desde entonces ha quedado en desuso y posteriormente eliminado de POSIX; para el nuevo código, nanosleep()se prefiere:

   #include <time.h>

   int nanosleep(const struct timespec *req, struct timespec *rem);

DESCRIPCIÓN

nanosleep()suspende la ejecución del hilo de llamada hasta que *reqhaya transcurrido al menos el tiempo especificado , o la entrega de una señal que active la invocación de un controlador en el hilo de llamada o que finalice el proceso.

La estructura timepec se usa para especificar intervalos de tiempo con precisión de nanosegundos. Se define de la siguiente manera:

       struct timespec {
           time_t tv_sec;        /* seconds */
           long   tv_nsec;       /* nanoseconds */
       };

Una msleep()función de ejemplo implementada usando nanosleep(), continuando el sueño si es interrumpido por una señal:

#include <time.h>
#include <errno.h>    

/* msleep(): Sleep for the requested number of milliseconds. */
int msleep(long msec)
{
    struct timespec ts;
    int res;

    if (msec < 0)
    {
        errno = EINVAL;
        return -1;
    }

    ts.tv_sec = msec / 1000;
    ts.tv_nsec = (msec % 1000) * 1000000;

    do {
        res = nanosleep(&ts, &ts);
    } while (res && errno == EINTR);

    return res;
}
coste y flete
fuente
19
¿Por qué siguen despreciando funciones simples para funciones complicadas? En lugar de reventar sus cerebros en nanosegundos (), bien podría usar usleep por el momento.
52

Puede usar esta función multiplataforma:

#ifdef WIN32
#include <windows.h>
#elif _POSIX_C_SOURCE >= 199309L
#include <time.h>   // for nanosleep
#else
#include <unistd.h> // for usleep
#endif

void sleep_ms(int milliseconds) // cross-platform sleep function
{
#ifdef WIN32
    Sleep(milliseconds);
#elif _POSIX_C_SOURCE >= 199309L
    struct timespec ts;
    ts.tv_sec = milliseconds / 1000;
    ts.tv_nsec = (milliseconds % 1000) * 1000000;
    nanosleep(&ts, NULL);
#else
    usleep(milliseconds * 1000);
#endif
}
Bernardo Ramos
fuente
3
Cuando no tenemos _POSIX_C_SOURCE >= 199309L, como en el caso de -ansio -std=c89, recomendaría usar en struct timeval tv; tv.tv_sec = milliseconds / 1000; tv.tv_usec = milliseconds % 1000 * 1000; select(0, NULL, NULL, NULL, &tv);lugar de usleep(milliseconds * 1000);. El crédito va aquí .
Josh Sanford
¡Gran respuesta! Tenga en cuenta que aquí está la nanosleep()documentación: man7.org/linux/man-pages/man2/nanosleep.2.html . Publicar los enlaces de documentación para cada función específica de plataforma utilizada aquí sería útil.
Gabriel Staples
También tenga en cuenta que cuando se compila con gcc -Wall -g3 -std=c11 -o sleep_test sleep_test.c && ./sleep_testel Linux Ubuntu, la versión de gcc 4.8.4, aparece el siguiente aviso: warning: implicit declaration of function ‘usleep’ [-Wimplicit-function-declaration]. La solución es agregar las siguientes 2 definiciones en la parte superior de su código: 1) #define __USE_POSIX199309y 2) #define _POSIX_C_SOURCE 199309L. Ambos son necesarios para que el código se compile sin advertencias (y también para usar la nanoseconds()función, que tiene disponible).
Gabriel Staples
Respuesta relacionada que acabo de hacer: stackoverflow.com/a/55860234/4561887
Gabriel Staples
32

Alternativamente usleep(), que no está definido en POSIX 2008 (aunque se definió hasta POSIX 2004, y evidentemente está disponible en Linux y otras plataformas con un historial de cumplimiento POSIX), el estándar POSIX 2008 define nanosleep():

nanosleep - sueño de alta resolución

#include <time.h>
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);

La nanosleep()función hará que el hilo actual se suspenda de la ejecución hasta que rqtphaya transcurrido el intervalo de tiempo especificado por el argumento o se entregue una señal al hilo llamante, y su acción es invocar una función de captura de señal o finalizar el proceso. El tiempo de suspensión puede ser más largo que el solicitado porque el valor del argumento se redondea a un múltiplo entero de la resolución de suspensión o debido a la programación de otra actividad por parte del sistema. Pero, a excepción del caso de ser interrumpido por una señal, el tiempo de suspensión no será inferior al tiempo especificado por rqtp, medido por el reloj del sistema CLOCK_REALTIME.

El uso de la nanosleep()función no tiene efecto sobre la acción o el bloqueo de ninguna señal.

Jonathan Leffler
fuente
24

Más allá de usleep , la selección humilde con conjuntos de descriptores de archivo NULL le permitirá pausar con precisión de microsegundos y sin riesgo de SIGALRMcomplicaciones.

sigtimedwait y sigwaitinfo ofrecen un comportamiento similar.

pilcrow
fuente
1
'sin riesgo de sigalarm': ¿qué riesgo y qué caso? llamando dormir y usleep?
Massimo
2
@ Massimo, la especificación vinculada para usleep tiene varias oraciones sobre el comportamiento SIGALARM no especificado. (Básicamente, se permite que usleep y sleep se implementen a través del antiguo mecanismo de alarma , lo que puede imaginar que complicaría el uso seguro de usleep y SIGALARM. No conozco ningún sistema moderno que lo haga de esta manera, pero aún está en el spec.)
Pilcrow
14
#include <unistd.h>

int usleep(useconds_t useconds); //pass in microseconds
Jonathan Leffler
fuente
-7
#include <stdio.h>
#include <stdlib.h>
int main () {

puts("Program Will Sleep For 2 Seconds");

system("sleep 2");      // works for linux systems


return 0;
}
Odin
fuente
1
Esto no durará milisegundos y también introduce mucha más sobrecarga, lo que hace que el tiempo sea aún más poco confiable.
Devolus
1
El ejemplo no duerme por microsegundos, además, esta no es una buena solución en comparación con solo usar algo como usleep ().
Victor Ocampo