Я пытаюсь убедиться, что время выполнения каждого цикла до 10 мс с usleep, но иногда оно превышает 10 мс.
Я понятия не имею, как решить эту проблему, это правильно использовать ты спишь а также gettimeofday в этом случае?
Пожалуйста, помогите мне выяснить, что я пропустил.
Результат: 0.0127289
0.0136499
0.0151598
0.0114031
0.014801
double tvsecf(){
struct timeval tv;
double asec;
gettimeofday(&tv,NULL);
asec = tv.tv_usec;
asec /= 1e6;
asec += tv.tv_sec;
return asec;
}
int main(){
double t1 ,t2;
t1 = tvsecf();
for(;;){
t2= tvsecf();
if(t2-t1 >= 0.01){
if(t2-t1 >= 0.011)
cout << t2-t1 <<endl;
t1 = tvsecf();
}
usleep(100);
}
}
Чтобы избежать накладных расходов цикла (которые обычно неизвестны) от постоянно накапливающейся ошибки, вы можете спать до тех пор время точка, вместо за время продолжительность. Использование C ++ <chrono>
а также <thread>
библиотеки, это невероятно легко:
#include <chrono>
#include <iostream>
#include <thread>
int
main()
{
using namespace std;
using namespace std::chrono;
auto t0 = steady_clock::now() + 10ms;
for (;;)
{
this_thread::sleep_until(t0);
t0 += 10ms;
}
}
Можно одеть это с большим количеством звонков steady_clock::now()
чтобы определить время между итерациями и, что еще важнее, средний время итерации:
#include <chrono>
#include <iostream>
#include <thread>
int
main()
{
using namespace std;
using namespace std::chrono;
using dsec = duration<double>;
auto t0 = steady_clock::now() + 10ms;
auto t1 = steady_clock::now();
auto t2 = t1;
constexpr auto N = 1000;
dsec avg{0};
for (auto i = 0; i < N; ++i)
{
this_thread::sleep_until(t0);
t0 += 10ms;
t2 = steady_clock::now();
dsec delta = t2-t1;
std::cout << delta.count() << "s\n";
avg += delta;
t1 = t2;
}
avg /= N;
cout << "avg = " << avg.count() << "s\n";
}
Выше я добавил к издержкам цикла, делая больше вещей в цикле. Однако цикл все еще собирается проснуться около каждые 10 мс. Иногда ОС просыпает поток поздно, но в следующий раз цикл автоматически настраивается на более короткий период сна. Таким образом, средняя скорость итерации автоматически корректируется до 10 мс.
На моей машине это просто вывод:
...
0.0102046s
0.0128338s
0.00700504s
0.0116826s
0.00785826s
0.0107023s
0.00912614s
0.0104725s
0.010489s
0.0112545s
0.00906409s
avg = 0.0100014s
Нет способа гарантировать время цикла 10 мс.
Все спящие функции спят в течение, по крайней мере, желаемого времени.
Для портативного решения используйте станд :: this_thread :: sleep_for
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
for (;;) {
auto start = std::chrono::high_resolution_clock::now();
std::this_thread::sleep_for(std::chrono::milliseconds{10});
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> elapsed = end-start;
std::cout << "Waited " << elapsed.count() << " ms\n";
}
}
В зависимости от того, что вы пытаетесь сделать, посмотрите на Говард Хиннантс библиотека дат.
От usleep man page:
Время ожидания может быть немного увеличено из-за любой системной активности или из-за времени, потраченного на обработку вызова, или из-за гранулярности системных таймеров.
Если вам нужно высокое разрешение: с C на Unix (или Linux) посмотрите этот ответ это объясняет, как использовать таймеры высокого разрешения с помощью clock_gettime.
Редактировать: как упомянуто Тобиасом nanosleep может быть лучшим вариантом:
Compared to sleep(3) and usleep(3), nanosleep() has the following
advantages: it provides a higher resolution for specifying the sleep
interval; POSIX.1 explicitly specifies that it does not interact with
signals; and it makes the task of resuming a sleep that has been
interrupted by a signal handler easier.