Existe uma função de sono alternativa em C a milissegundos?

133

Eu tenho algum código fonte que foi compilado no Windows. Estou convertendo para rodar no Red Hat Linux.

O código fonte incluiu o <windows.h>arquivo de cabeçalho e o programador usou a Sleep()função para aguardar um período de milissegundos. Isso não vai funcionar no Linux.

No entanto, eu posso usar a sleep(seconds)função, mas isso usa inteiro em segundos. Não quero converter milissegundos em segundos. Existe uma função de suspensão alternativa que eu possa usar com a compilação do gcc no Linux?

ant2009
fonte
sleep(/*seconds*/)em <unistd.h>obras, mas se eu usar com printf("some things")sem \n, não funciona.
EsmaeelE
Para uso neste caso, precisamos liberar a saída fflush(stdout);após cada umprintf()
EsmaeelE 26/11/17

Respostas:

179

Sim - padrões POSIX mais antigos definidos usleep(), portanto, isso está disponível no Linux:

   int usleep(useconds_t usec);

DESCRIÇÃO

A função usleep () suspende a execução do encadeamento de chamada por (pelo menos) microssegundos de usec. O sono pode ser prolongado levemente por qualquer atividade do sistema ou pelo tempo gasto no processamento da chamada ou pela granularidade dos cronômetros do sistema.

usleep()leva microssegundos , então você terá que multiplicar a entrada por 1000 para dormir em milissegundos.


usleep()foi descontinuado e removido do POSIX; para novo código, nanosleep()é preferido:

   #include <time.h>

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

DESCRIÇÃO

nanosleep()suspende a execução do encadeamento de chamada até que pelo menos o tempo especificado *reqtenha decorrido ou a entrega de um sinal que dispara a chamada de um manipulador no encadeamento de chamada ou que encerre o processo.

A estrutura timespec é usada para especificar intervalos de tempo com precisão de nanossegundos. É definido da seguinte forma:

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

Um exemplo de msleep()função implementada usando nanosleep(), continuando o sono, se for interrompido por um sinal:

#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;
}
caf
fonte
19
Por que eles continuam reprovando funções simples para funções complicadas. Em vez de quebrar o cérebro em nanossegundos (), é melhor usar o sono por enquanto.
52

Você pode usar esta função de plataforma cruzada:

#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
fonte
3
Quando não temos _POSIX_C_SOURCE >= 199309L, como no caso de -ansiou -std=c89, eu recomendaria usar em struct timeval tv; tv.tv_sec = milliseconds / 1000; tv.tv_usec = milliseconds % 1000 * 1000; select(0, NULL, NULL, NULL, &tv);vez de usleep(milliseconds * 1000);. O crédito vai aqui .
Josh Sanford
Ótima resposta! Observe, aqui está a nanosleep()documentação: man7.org/linux/man-pages/man2/nanosleep.2.html . A publicação dos links da documentação para cada função específica da plataforma usada aqui seria útil.
Gabriel Staples
Observe também que quando compilando com gcc -Wall -g3 -std=c11 -o sleep_test sleep_test.c && ./sleep_testno Linux Ubuntu, com gcc versão 4.8.4, eu recebo o seguinte aviso: warning: implicit declaration of function ‘usleep’ [-Wimplicit-function-declaration]. A solução é adicionar as 2 seguintes definições ao topo do seu código: 1) #define __USE_POSIX199309e 2) #define _POSIX_C_SOURCE 199309L. Ambos são necessários para que o código seja compilado sem nenhum aviso (e também para usar a nanoseconds()função que ele tem disponível).
Gabriel Staples
Resposta relacionada que acabei de fazer: stackoverflow.com/a/55860234/4561887
Gabriel Staples
32

Como alternativa usleep(), que não está definida no POSIX 2008 (embora tenha sido definida até o POSIX 2004 e esteja evidentemente disponível no Linux e outras plataformas com histórico de conformidade com o POSIX), o padrão POSIX 2008 define nanosleep():

nanosleep - sono de alta resolução

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

A nanosleep()função deve fazer com que o encadeamento atual seja suspenso da execução até que o intervalo de tempo especificado pelo rqtpargumento tenha decorrido ou um sinal seja entregue ao encadeamento de chamada, e sua ação é invocar uma função de captura de sinal ou finalizar o processo. O tempo de suspensão pode ser maior que o solicitado, porque o valor do argumento é arredondado para um múltiplo inteiro da resolução de suspensão ou devido ao agendamento de outras atividades pelo sistema. Mas, exceto no caso de ser interrompido por um sinal, o tempo de suspensão não deve ser menor que o tempo especificado por rqtp, conforme medido pelo relógio do sistema CLOCK_REALTIME.

O uso da nanosleep()função não afeta a ação ou o bloqueio de qualquer sinal.

Jonathan Leffler
fonte
24

Além do sono , a seleção humilde com os conjuntos de descritores de arquivos NULL permitirá pausar com precisão de microssegundos e sem o risco de SIGALRMcomplicações.

sigtimedwait e sigwaitinfo oferecem comportamento semelhante.

Pilcrow
fonte
1
'sem o risco de sigalarm': qual risco e qual caso? chamando sono e sono?
Massimo
2
@ Massimo, a especificação vinculada para usleep possui várias frases sobre o comportamento não especificado do SIGALARM. (Basicamente, usleep e sleep podem ser implementados por meio do mecanismo de alarme antigo , o que você pode imaginar complicaria o uso seguro de usleep e SIGALARM. Não conheço nenhum sistema moderno que faça dessa maneira, mas ele ainda está no )
pilcrow
14
#include <unistd.h>

int usleep(useconds_t useconds); //pass in microseconds
Jonathan Leffler
fonte
-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
fonte
1
Isso não dorme por milissegundos e também introduz muito mais sobrecarga, o que torna o tempo ainda mais confiável.
Devolus
1
O exemplo não dorme por microssegundos, mais isso não é uma solução tão boa em comparação com o uso de algo como usleep ().
Victor Ocampo