точный сон / ожидание. Windows ОС. 1мс. точность - PullRequest
0 голосов
/ 24 марта 2020

У меня есть программа, где ожидание / задержка должны быть точными. Проблема, с которой я сталкиваюсь, связана с изменениями в режиме ожидания / задержки на разных компьютерах (я понимаю, что причиной этого могут быть различия частоты процессора). Мне было интересно, может ли кто-нибудь указать мне правильное направление, чтобы я мог найти точный режим ожидания компьютера. Я также понимаю, что точность 1 мс невозможна в ОС windows, потому что она не в реальном времени, использование процессора также является проблемой, так что я скорее не сплю. (c ++ lang)

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 - 0.516) * 10000.0f);
    NtDelayExecution(false, &interval);
}

Я нашел это по аналогичному вопросу, задаваемому

interval.QuadPart = -1 * (int)((milliseconds - 0.516) * 10000.0f);

. Похоже, что -0,516 точно соответствует тому, что я делаю на своем компьютере, по крайней мере. Это ожидание / сон используется для 1 мс сна.

Ответы [ 2 ]

0 голосов
/ 24 марта 2020

Если это вообще возможно, я рекомендую использовать <chrono>, так как во время компиляции вы поймете так много ошибок и упростите логи c.

Далее я рекомендую комбинацию использования ОС для сна и "горячий сон". Короче говоря, используйте ОС для сна до некоторого короткого интервала до желаемого времени пробуждения, а затем вращайтесь в течение последнего небольшого интервала времени. Я использую 1 мс для последнего интервала вращения, мммм.

#include <chrono>
#include <iostream>
#include <thread>

void
SleepShort(std::chrono::duration<float, std::milli> d)
{
    using namespace std::chrono;
    auto t = steady_clock::now() + ceil<steady_clock::duration>(d);
    if (d > 1ms)
        std::this_thread::sleep_until(t-1ms);
    while (steady_clock::now() < t)
        ;
}

Одна ошибка, с которой я столкнулся при разработке кода выше, избегала отсутствия необходимой точности в float. У меня изначально был такой код:

auto t = steady_clock::now() + d;

, который неявно создает time_point с rep из float и периодом nanoseconds, измеряющим время, прошедшее с момента загрузки компьютера (на моей платформе). ). Оказывается, что float не обладает точностью, необходимой для представления этой величины. Впоследствии мой спин l oop не работал.

Переключение на ceil, как показано, преобразует миллисекунды с плавающей запятой в целочисленные тики, которые использует steady_clock (nanoseconds во всех 3 основных реализациях), и теперь арифметика c имеет достаточную точность для правильной работы. Fwiw, double также работал бы нормально.

Это можно назвать так:

SleepShort(2.5ms);
0 голосов
/ 24 марта 2020
#include <chrono>

Глобальное пространство:

class bla{
    double time;
    std::chrono::steady_clock::time_point start_clock;
    void upd_clock(){
        std::chrono::steady_clock::time_point current_time = std::chrono::steady_clock::now();
        time = ((double) std::chrono::duration_cast<std::chrono::miliseconds>(current_time - start_clock).count())/1000;
    }
}

В основном:

bla->start_clock = std::chrono::steady_clock::now();

И в основном l oop:

while(1){
    bla->upd_clock();
}

bla-> время сохраняет время. Эксперимент с милисекундами / микро и др. c. Это то, как вы измеряете время. Если он идет спать - не укладывайте нить в сон - пробуждение займет намного больше времени, чем ваша цель. Вы можете сохранить основной поток работающим только с обновлением часов и проверкой времени. Еще одна вещь: на одинаковых интервалах измерения времени вы могли бы написать это с int64 вместо double.

...