Pergunta

No Windows Eu tenho um problema que eu nunca encontrou em Unix. Isso é como obter um fio para dormir por menos de um milissegundo. No Unix você geralmente têm uma série de opções (sono, usleep e nanosleep) para atender às suas necessidades. No Windows, no entanto, há apenas Sleep com granularidade milissegundo.

No Unix, eu posso usar o uso da chamada de sistema select para criar um sono microssegundo que é bastante simples:

int usleep(long usec)
{
    struct timeval tv;
    tv.tv_sec = usec/1000000L;
    tv.tv_usec = usec%1000000L;
    return select(0, 0, 0, 0, &tv);
}

Como posso conseguir o mesmo no Windows?

Foi útil?

Solução 18

No Windows o uso de forças select você para incluir o biblioteca Winsock que tem de ser inicializado como este em sua aplicação:

WORD wVersionRequested = MAKEWORD(1,0);
WSADATA wsaData;
WSAStartup(wVersionRequested, &wsaData);

E então o selecione não vai permitir que você seja chamado sem qualquer tomada de modo que você tem que fazer um pouco mais para criar um método microsleep:

int usleep(long usec)
{
    struct timeval tv;
    fd_set dummy;
    SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    FD_ZERO(&dummy);
    FD_SET(s, &dummy);
    tv.tv_sec = usec/1000000L;
    tv.tv_usec = usec%1000000L;
    return select(0, 0, 0, &dummy, &tv);
}

Todos estes métodos criados usleep retornar zero quando bem sucedido e diferente de zero para erros.

Outras dicas

Isso indica uma mis-compreensão das funções do sono. O parâmetro que você passa é uma mínimo tempo para dormir. Não há nenhuma garantia de que o segmento vai acordar depois exatamente o tempo especificado. Na verdade, tópicos não 'acordar' em tudo, mas são bastante escolhido para execução pelo programador. O programador pode optar por esperar muito mais tempo do que a duração do sono solicitado para ativar um fio, especialmente se outro segmento ainda está ativo no momento.

Como Joel diz, você não pode significativamente 'dormir' (ou seja, abandonar o seu CPU programada) por um período tão curto. Se você quiser atraso por algum curto espaço de tempo, então você precisa rotação, repetidamente verificando um temporizador adequadamente alta resolução (por exemplo, o 'timer desempenho') e esperando que algo de alta prioridade não antecipar-se de qualquer maneira.

Se você realmente se preocupam com atrasos exacta desses tempos curtos, você não deve estar usando o Windows.

Use os temporizadores de alta resolução disponíveis em Winmm.lib. Consulte este para um exemplo.

Sim, você precisa entender o seu sistema operacional' quantums tempo. No Windows, você não vai mesmo estar recebendo o tempo de resolução de 1ms menos que você altere o quantum de tempo de 1 ms. (Usando, por exemplo timeBeginPeriod () / timeEndPeriod ()) Isso ainda realmente não vai garantir nada. Mesmo um pouco de carga ou um único driver de dispositivo de baixa qualidade vai jogar tudo fora.

SetThreadPriority () ajuda, mas é bastante perigoso. drivers de dispositivo ruins ainda pode arruiná-lo.

Você precisa de um ambiente ultra-controlado de computação para fazer este trabalho coisas feias em tudo.

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

sim ele usa algumas funções do kernel sem documentos, mas ele funciona muito bem, eu uso SleepShort (0,5); em alguns dos meus threds

Se você quer tanto granularidade você está no lugar errado (no espaço do usuário).

Lembre-se que se você estiver no espaço do usuário o seu tempo nem sempre é preciso.

O programador pode começar seu segmento (ou aplicativo), e programá-lo, então você está dependendo do programador OS.

Se você está procurando algo precisa você tem que ir: 1) No kernel do espaço (como motoristas) 2) Escolha um RTOS.

De qualquer forma, se você estiver procurando por algum granularidade (mas lembre-se o problema com o espaço do usuário) olhar para Função QueryPerformanceCounter e função QueryPerformanceFrequency no MSDN.

Como várias pessoas têm para fora pontas, sono e outras funções relacionadas são por dependentes da "marcação sistema" padrão. Esta é a unidade mínima de tempo entre as tarefas do sistema operacional; o programador, por exemplo, não irá correr mais rápido do que isso. Mesmo com um sistema operacional em tempo real, o sistema de carrapato geralmente não é inferior a 1 ms. Embora seja ajustável, isto tem implicações para o sistema inteiro, não apenas a sua funcionalidade sono, porque o seu programador será executado com mais freqüência, e aumentando potencialmente a sobrecarga de seu sistema operacional (quantidade de tempo para o Scheduler para executar, quantidade vs. de vez que uma tarefa pode ser executada).

A solução para isso é usar, um dispositivo de relógio de alta velocidade externo. A maioria dos sistemas Unix irá permitir que você especifique a seus temporizadores e um relógio de tão diferente para uso, em oposição ao relógio do sistema padrão.

O que você está esperando que exige tanta precisão? Em geral, se você necessidade para especificar que nível de precisão (por exemplo, por causa de uma dependência em algum hardware externo) está na plataforma errada e deve olhar para um sistema operacional de tempo real.

Caso contrário, você deve considerar se há um evento que você pode sincronizar on, ou na pior das hipóteses apenas ocupado espera da CPU e usar o contador de alto desempenho API para medir o tempo decorrido.

Geralmente um sono vai durar pelo menos até o próximo sistema de interrupção ocorre. No entanto, este depende das configurações dos recursos do temporizador multimédia. Pode ser definido para algo perto de 1 ms, algum hardware ainda permite executar em períodos de interrupção de 0,9765625 ( ActualResolution fornecido pelo NtQueryTimerResolution irá mostrar 0,9766, mas que é realmente errado. Eles simplesmente não pode colocar o número correto para o ActualResolution formato. É 0.9765625ms em 1024 interrupções por segundo).

Há uma exceção wich nos permite escapar do fato de que ele pode ser impossível dormir por menos do que o período de interrupção: É o famoso Sleep(0). Este é um poderoso ferramenta e não é usado tão frequentemente como deveria! Ele abandona o lembrete de fatia de tempo do segmento. Desta forma, o segmento vai parar até que o programador obriga o fio para obter serviço de cpu novamente. Sleep(0) é um serviço assíncrono, a chamada irá forçar o programador para reagir independente de uma interrupção.

A segunda maneira é o uso de um waitable object. A função de espera como WaitForSingleObject() pode esperar por um evento. Para se ter um sono tópico por qualquer tempo, também vezes no regime microssegundo, as necessidades de rosca para configurar alguma linha de serviço que irá gerar um evento no atraso desejado. O "dormir" setup fio vontade esta discussão e, em seguida, fazer uma pausa na função de espera até que o segmento serviço irá definir o evento sinalizado.

Desta forma, qualquer thread pode "dormir" ou espera para qualquer momento. O segmento de serviço pode ser de grande complexidade e que podem oferecer serviços a nível do sistema como eventos programados na resolução de microsegundos. No entanto, a resolução microssegundo pode forçar o thread de serviço para rotação sobre um serviço de tempo de alta resolução para no máximo um período de interrupção (~ 1 ms). Se cuidado é tomado, isso pode correr muito bem, especialmente em multi-processador ou sistemas de multi-core. A um ms rotação não faz mal consideravelmente em sistema multi-core, quando a máscara de afinidade para o segmento de chamada e o segmento de serviço são cuidadosamente tratadas.

código, descrição, e os testes podem ser visitadas no do Windows Projeto Timestamp

Eu tenho o mesmo problema e nada parece ser mais rápido que um ms, mesmo o Sleep (0). Meu problema é a comunicação entre um cliente e um aplicativo de servidor onde eu uso a função _InterlockedExchange para testar e ajustar um pouco e então eu Sleep (0).

Eu realmente preciso para executar milhares de operações por segundo para um lado e ele não funciona tão rápido como eu planejei.

Desde que eu tenho um thin client lidar com o usuário, que por sua vez invoca um agente que, em seguida, fala com um fio, eu vou mudar em breve para fundir o fio com o agente de modo que será necessária nenhuma interface evento.

Apenas para dar a vocês uma idéia de como retardar esse sono é, eu corri um teste por 10 segundos executar um loop vazio (recebendo algo como 18.000.000 voltas), enquanto que com o evento no lugar Eu só tem 180.000 loops. Ou seja, 100 vezes mais lento!

Na verdade usando esta função usleep irá causar um vazamento de grande memória / recursos. (Dependendo de como muitas vezes chamado)

usar esta versão corrigida (desculpe não pode editar?)

bool usleep(unsigned long usec)
{
    struct timeval tv;
    fd_set dummy;
    SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    FD_ZERO(&dummy);
    FD_SET(s, &dummy);
    tv.tv_sec = usec / 1000000ul;
    tv.tv_usec = usec % 1000000ul;
    bool success = (0 == select(0, 0, 0, &dummy, &tv));
    closesocket(s);
    return success;
}

Como todos mencionados, há de fato nenhuma garantia sobre o tempo de sono. Mas ninguém quer admitir que, por vezes, em um sistema ocioso, o comando usleep pode ser muito preciso. Especialmente com um kernel tickless. Windows Vista tem e Linux tem desde 2.6.16.

Tickless kernels existe para ajudar a melhorar laptops vida batterly: c.f. utility powertop da Intel.

Nessa condição, eu aconteceu a ter medido comando do Linux usleep que respeitado o tempo de sono solicitado muito de perto, até a meia dúzia de micro segundos.

Assim, talvez o OP quer algo que vai mais ou menos trabalhar a maior parte do tempo em um sistema em marcha lenta, e ser capaz de pedir segunda agendamento micro! Na verdade, eu gostaria que no Windows também.

Além disso Sleep (0) soa como boost :: Thread :: rendimento (), que a terminologia é mais clara.

Gostaria de saber se impulsionar fechaduras -timed ter uma melhor precisão. Porque então você poderia simplesmente bloquear um mutex que ninguém nunca lançamentos, e quando o tempo limite é atingido, continuar ... Tempos limite são definidos com boost :: system_time + boost :: milissegundos & Cie (xtime está obsoleta).

Tente usar SetWaitableTimer ...

Tente boost :: xtime e uma TIMED_WAIT ()

tem uma precisão de nanossegundos.

Apenas uso Sleep (0). 0 é claramente inferior a um milissegundo. Agora, isso soa engraçado, mas eu sou sério. Sleep (0) informa ao Windows que você não tem nada a ver agora, mas que você quer ser reconsiderada assim que o programador é executado novamente. E uma vez que, obviamente, o segmento não pode ser programado para ser executado antes do próprio programador é executado, este é o menor atraso possível.

Note que você pode passar em um número de microssegundos para o seu usleep, mas o mesmo acontece usleep void (__ int64 t) {Sleep (t / 1000); } -. Há garantias para realmente dormindo esse período

Função dormir que é muito menos do que um milésimo de segundo, talvez

Eu achei que o sono (0) trabalhou para mim. Em um sistema com uma carga perto de 0% na CPU no Gerenciador de tarefas, eu escrevi um simples programa de console e o sono função (0) dormido por uma consistente 1-3 microssegundos, que é muito menos do que um milésimo de segundo.

Mas a partir das respostas acima neste tópico, eu sei que a quantidade de sono (0) dorme pode variar muito mais descontroladamente do que isso em sistemas com uma grande carga de CPU.

Mas, como eu a entendo, a função de suspensão não deve ser usado como um timer. Ele deve ser usado para fazer o programa usar a menor porcentagem da CPU possível e executar tão frequentemente quanto possível. Para os meus propósitos, como mover um projétil através da tela em um videogame muito mais rápido do que um pixel um milésimo de segundo, o sono (0) obras, eu acho.

Você apenas certifique-se o intervalo de suspensão é muito menor do que a maior quantidade de tempo que iria dormir. Você não usar o sono como um temporizador, mas apenas para fazer o jogo usam a quantidade mínima de porcentagem de CPU possível. Você usaria uma função separada que nada tem a fazer é dormir para conhecer quando uma determinada quantidade de tempo passou e, em seguida, mover o projétil um pixel em toda a tela, em um momento de digamos 1 / 10th de um milésimo de segundo ou 100 microssegundos .

O pseudo-código seria algo como isto.

while (timer1 < 100 microseconds) {
sleep(0);
}

if (timer2 >=100 microseconds) {
move projectile one pixel
}

//Rest of code in iteration here

Eu sei a resposta pode não funcionar para problemas avançados, ou programas, mas pode funcionar para alguns ou muitos programas.

Se o seu objetivo é "espera por um período muito curto de tempo" , porque você está fazendo um SpinWait , então não estão aumentando os níveis de espera você pode executar.

void SpinOnce(ref Int32 spin)
{
   /*
      SpinOnce is called each time we need to wait. 
      But the action it takes depends on how many times we've been spinning:

      1..12 spins: spin 2..4096 cycles
      12..32: call SwitchToThread (allow another thread ready to go on time core to execute)
      over 32 spins: Sleep(0) (give up the remainder of our timeslice to any other thread ready to run, also allows APC and I/O callbacks)
   */
   spin += 1;

   if (spin > 32)
      Sleep(0); //give up the remainder of our timeslice
   else if (spin > 12)
      SwitchTothread(); //allow another thread on our CPU to have the remainder of our timeslice
   else
   {
      int loops = (1 << spin); //1..12 ==> 2..4096
      while (loops > 0)
         loops -= 1;
   }
}

Portanto, se seu objetivo é realmente a espera apenas para um pouco , você pode usar algo como:

int spin = 0;
while (!TryAcquireLock()) 
{ 
   SpinOne(ref spin);
}

A virtude aqui é que nós esperar mais de cada vez, acabou indo completamente a dormir.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top