c++, usleep () устарел, обходные пути для Windows/MingW?

Я уже выяснил с другим вопросом, что Windows / MingW не предоставляет альтернативы nanosleep() и setitimer() для устаревшего usleep(). Но моя цель-исправить все предупреждения, которые cppcheck дает мне, включая предупреждения стиля usleep ().

Так, есть ли обходной путь, чтобы как-то избежать usleep() в Windows без использование cygwin или установка нагрузок новых зависимостей/библиотек? Спасибо.

6 ответов


usleep() работает с МКС. В windows для получения микросекундной прецессии вы должны использовать QueryPerformanceCounter() функция winapi. здесь вы можете найти, как сделать, что precesion, используя его.


я использовал этот код (родом из здесь):

#include <windows.h>

void usleep(__int64 usec) 
{ 
    HANDLE timer; 
    LARGE_INTEGER ft; 

    ft.QuadPart = -(10*usec); // Convert to 100 nanosecond interval, negative value indicates relative time

    timer = CreateWaitableTimer(NULL, TRUE, NULL); 
    SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0); 
    WaitForSingleObject(timer, INFINITE); 
    CloseHandle(timer); 
}

отметим, что SetWaitableTimer() использует "100 наносекундных интервалов ... Положительные значения указывают на абсолютное время. ... Отрицательные значения указывают на относительное время." и "фактическая точность таймера зависит от возможностей вашего оборудования."

если у вас есть компилятор C++11, вы можете использовать этой портативное версия:

#include <chrono>
#include <thread>
...
std::this_thread::sleep_for(std::chrono::microseconds(usec));

престижность объектов Ховард, который создал удивительный <chrono> библиотека (и ответ на который ниже заслуживает больше любви.)

если у вас нет C++11, но у вас есть boost, то вы можете сделать этой вместо:

#include <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
...
boost::this_thread::sleep(boost::posix_time::microseconds(usec));

режим миллисекунду Sleep() функция хорошо описана и хорошо понята. Он не делает ничего непредсказуемого. Иногда функцию обвиняют в непредсказуемости, т. е. в возврате до истечения срока задержки. Я должен сказать, что это неправильно. Тщательное расследование подтвердит, что его поведение абсолютно предсказуемо. Единственная проблема что существует много читала об этом и по-детски. Также часто говорят, что windows это не ОС реального времени. Но такие комментарии ничего не дают, более того такие комментарии используются для того, чтобы скрыть отсутствие знаний. Это меня злит, что даже microsoft замечает это и предоставляет лучшую документацию.

однако, не преувеличивая этот маленький ответ: функция sleep() точна, когда используется надлежащим образом и когда знает ее характеристики. Особое внимание следует уделить сну(0). Это очень мощный инструмент, особенно при использовании вместе с Процесс класс приоритета, приоритет потока, настройки мультимедийного таймера и процессора маски.

так вообще истинный сон можно выполнить легко и безопасно вниз к периоду прерывания систем. Когда дело доходит до спит короче, чем период прерывания спиннинг требуется. Источник времени с более высоким разрешением должен использоваться в oder для вращения в течение более коротких периодов времени. Наиболее распространенным источником для этого является счетчик производительности. QueryPerformanceCounter(*arg) обеспечивает увеличение * arg. QueryPerformanceFrequency(*arg) доставляет частота, с которой счетчик производительности увеличивается. Это, как правило, в режиме МГц и варьируется в зависимости от базового оборудования. Частота в диапазоне Мгц обеспечивает микросекундное разрешение. Таким образом, что-то с высоким разрешением можно использовать для ожидания желаемого промежутка времени. Однако точность этого следует тщательно изучить: ОС возвращает частоту счетчика производительности как константу. Это неправильно! Поскольку частота генерируется физическим устройством, там всегда смещение и оно также не a постоянный. Он имеет термальный дрейф. Более современные системы имеют меньший дрейф. Но если тепловой дрейф составляет всего 1ppm, ошибка будет 1us / s. Смещение может легко быть несколько 100. Смещение 100 в 1MHz соответствует 100us / s.

если поток должен ждать в любое время с высоким разрешением, он должен установить служебный поток. Оба потока должны совместно использовать именованное событие. Поток обслуживания будет спать до 1 периода прерывания перед пожеланным сном задержка, а затем вращение на счетчике производительности в течение оставшейся микросекунды. Когда поток службы достигает последнего времени, он устанавливает именованное событие и завершается. Вызывающий поток проснется, потому что он ждал именованного события с помощью функции wait.

резюме:

  • сон хорошо понимается, но плохо документируется.
  • служебный поток может имитировать спящие с высоким разрешением.
  • такой поток обслуживания coulb быть esablished как общесистемный сервис.
  • точность счетчика производительности следует внимательно изучить. Необходима калибровка.

более подробную информацию можно найти в Проект Метки Времени Windows


новый ответ на старый вопрос:

обоснование нового ответа: инструменты / OSs были обновлены таким образом, что теперь есть лучший выбор, чем когда вопрос был первоначально задан.

C++11 <chrono> и <thread> заголовки std находятся в наборе инструментов VS уже несколько лет. Используя эти заголовки, это лучше всего закодировано в C++11 как:

std::this_thread::sleep_for(std::chrono::microseconds(123));

Я использую микросекунды только в качестве примера продолжительности. Вы можете использовать любую продолжительность чтобы быть удобным:

std::this_thread::sleep_for(std::chrono::minutes(2));

С C++14 и некоторыми директивами использования это можно написать немного компактнее:

using namespace std::literals;
std::this_thread::sleep_for(2min);

или:

std::this_thread::sleep_for(123us);

это определенно работает на VS-2013 (по модулю хроно-литералов). Я не уверен в более ранних версиях VS.


Это зависит от того, какая детализация вам нужна. Если вы говорите миллисекунды, то функция Win32 Sleep выполнит эту работу-см. http://msdn.microsoft.com/en-us/library/ms686298%28v=vs.85%29.aspx. Если вы говорите микросекунды, то нет простого способа сделать это, и Вам ПОВЕЗЕТ, чтобы получить такое разрешение таймера на Windows (которая не является RTOS) или на Linux, прийти к этому.


нашел это сообщение в блоге об этом. Он использует QueryPerformanceCounter. Функция опубликована:

#include <windows.h>

void uSleep(int waitTime) {
    __int64 time1 = 0, time2 = 0, freq = 0;

    QueryPerformanceCounter((LARGE_INTEGER *) &time1);
    QueryPerformanceFrequency((LARGE_INTEGER *)&freq);

    do {
        QueryPerformanceCounter((LARGE_INTEGER *) &time2);
    } while((time2-time1) < waitTime);
}

надеюсь, это немного поможет.