Подтвердить что ты не робот

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

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

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

4b9b3361

Ответ 1

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

Ответ 2

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

#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 наносекундных интервалов... Положительные значения указывают абсолютное время... Отрицательные значения указывают относительное время". и что "фактическая точность таймера зависит от возможностей вашего оборудования".

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

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

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

Если у вас нет С++ 11, но у вас есть стимул, вы можете вместо этого this:

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

Ответ 3

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

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

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

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

Резюме:

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

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

Ответ 4

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

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

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

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

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

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

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

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

или

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

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

Ответ 5

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

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

Ответ 6

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