c ++, usleep () устарел, обходные пути для Windows / MingW? - PullRequest
22 голосов
/ 27 апреля 2011

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

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

Ответы [ 6 ]

44 голосов
/ 24 июня 2013

Я использовал этот код (изначально здесь ):

#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, но у вас есть повышение, тогда вы можете сделать это вместо этого:

#include <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
...
boost::this_thread::sleep(boost::posix_time::microseconds(usec));
11 голосов
/ 31 августа 2015

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

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

Заголовки 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.

8 голосов
/ 13 июля 2012

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

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

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

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

Сводка:

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

Более подробную информацию можно найти в Windows Timestamp Project

4 голосов
/ 27 апреля 2011

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

4 голосов
/ 27 апреля 2011

Я нашел этот пост в блоге об этом .Он использует 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);
}

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

0 голосов
/ 27 апреля 2011

usleep() работает с микросекундами. В окнах для получения приоритета микросекунды вы должны использовать функцию QueryPerformanceCounter () winapi. Здесь вы можете найти, как получить это преимущество, используя его.

...