почему c ++ 11 sleep_for микросекунды фактически спят в течение миллисекунды? - PullRequest
4 голосов
/ 08 марта 2020

Я вызываю эту функцию на моем сервере centos 7.

Я нахожу, что std :: this_thread :: sleep_for (chrono :: наносекунд (1)) фактически спит в течение одной мс. Есть какое-либо объяснение? Я думаю, что это может быть вызвано настройкой ОС?

Ответы [ 3 ]

6 голосов
/ 08 марта 2020

Из документации sleep_for вы можете видеть, что:

Блокирует выполнение текущего потока для как минимум с указанным значением sleep_duration .

Эта функция может блокироваться дольше , чем sleep_duration, из-за задержек планирования или конфликта ресурсов.

Наиболее вероятная причина в том, что ваш планировщик процессов выбивает спящий поток и не перепланирует его в течение миллисекунды.

5 голосов
/ 08 марта 2020

Давайте сначала проверим, что дает вам спецификация (цитаты из последней версии стандарта C ++):

[thread.req.timing]

Реализации обязательно имеют некоторые задержка возврата из таймаута. Любые издержки в ответе на прерывание, возврате функции и планировании вызывают задержку «качества реализации», выраженную как длительность D i . В идеале эта задержка была бы равна нулю. Кроме того, любое соперничество за ресурсы процессора и памяти вызывает задержку «качества управления», выраженную как длительность D m . Длительность задержки может варьироваться от таймаута к таймауту, но во всех случаях чем короче, тем лучше.

Функции, имена которых заканчиваются на _for, принимают аргумент, который задает продолжительность. ... Учитывая аргумент продолжительности D t , длительность тайм-аута в реальном времени составляет D t + D i + D m .

Разрешение синхронизации, обеспечиваемое реализацией, зависит как от операционной системы, так и от аппаратного обеспечения. ...

Таким образом, ожидается, что время ожидания будет больше, чем D t , указанное в качестве аргумента.

Предполагая, что ваш тест был правильным, мы можем использовать его, чтобы вычислить, что D i + D m было около миллисекунды в вашей системе с вашим оборудованием в этом конкретном исполнении.

Есть ли любой простой метод может гарантировать, что я сплю 1us?

Нет, не в стандартном C ++ для всех систем.

Это может быть возможно в системе с поддержкой реального времени. См. Документацию системы, на которую вы ориентируетесь.

2 голосов
/ 08 марта 2020

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

Есть ли какой-нибудь простой метод, который может гарантировать, что я сплю 1us?

Вместо того, чтобы вызывать sleep_for, получая слот выполнения потока, вы могли бы спать-занято. То есть l oop, пока не пройдет определенное время. Зачастую он получит более точные результаты за счет того, что этот поток ЦП будет непригодным для выполнения чего-либо еще.

Вот один пример с функцией, называемой busy_sleep():

// get a rough estimate of how much overhead there is in calling buzy_sleep()
std::chrono::nanoseconds calc_overhead() {
    using namespace std::chrono;
    constexpr size_t tests = 1001;
    constexpr auto timer = 200us;

    auto init = [&timer]() {
        auto end = steady_clock::now() + timer;
        while(steady_clock::now() < end);
    };

    time_point<steady_clock> start;
    nanoseconds dur[tests];

    for(auto& d : dur) {
        start = steady_clock::now();
        init();
        d = steady_clock::now() - start - timer;
    }
    std::sort(std::begin(dur), std::end(dur));
    // get the median value or something a little less as in this example:
    return dur[tests / 3];
}

// initialize the overhead constant that will be used in busy_sleep()
static const std::chrono::nanoseconds overhead = calc_overhead();

inline void busy_sleep(std::chrono::nanoseconds t) {
    auto end = std::chrono::steady_clock::now() + t - overhead;
    while(std::chrono::steady_clock::now() < end);
}

Демо

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

...