Контролируйте время цикла с помощью usleep

Я пытаюсь убедиться, что время выполнения каждого цикла до 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);
}
}

0

Решение

Чтобы избежать накладных расходов цикла (которые обычно неизвестны) от постоянно накапливающейся ошибки, вы можете спать до тех пор время точка, вместо за время продолжительность. Использование 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
3

Другие решения

Нет способа гарантировать время цикла 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";
}
}

В зависимости от того, что вы пытаетесь сделать, посмотрите на Говард Хиннантс библиотека дат.

0

От 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.
0
По вопросам рекламы [email protected]