Установка скорости выполнения цикла while в коде С++ для синхронизации в реальном времени

Вопрос:Я выполняю симуляцию реального времени с использованием исходного кода .cpp. Я должен взять образец каждые 0,2 секунды (200 мс)... Существует цикл while, который принимает образец каждый шаг по времени... Я хочу синхронизировать выполнение этого цикла while, чтобы получить образец каждый ( 200 мс)... Как мне изменить цикл while? while (1){ // get a sample every

Вопрос:

Я выполняю симуляцию реального времени с использованием исходного кода .cpp. Я должен взять образец каждые 0,2 секунды (200 мс)… Существует цикл while, который принимает образец каждый шаг по времени… Я хочу синхронизировать выполнение этого цикла while, чтобы получить образец каждый ( 200 мс)… Как мне изменить цикл while?

while (1){ // get a sample every 200 ms } Лучший ответ:

то, что вы просите, сложно, если вы не используете операционную систему реального времени.

Однако у Boost есть библиотека, которая поддерживает то, что вы хотите. (Однако нет никакой гарантии, что вы будете называться ровно каждые 200 мс.

Библиотека Boost ASIO, вероятно, именно то, что вы ищете, вот код из их учебника:

// // timer.cpp // ~~~~~~~~~ // // Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // #include <iostream> #include <boost/asio.hpp> #include <boost/date_time/posix_time/posix_time.hpp> int main() { boost::asio::io_service io; boost::asio::deadline_timer t(io, boost::posix_time::seconds(5)); t.wait(); std::cout << «Hello, world!n»; return 0; }

ссылка здесь: ссылка для увеличения asio.

Вы можете взять этот код и перестроить его таким образом

#include <iostream> #include <boost/asio.hpp> #include <boost/date_time/posix_time/posix_time.hpp> int main() { boost::asio::io_service io; while(1) { boost::asio::deadline_timer t(io, boost::posix_time::seconds(5)); // process your IO here — not sure how long your IO takes, so you may need to adjust your timer t.wait(); } return 0; }

Существует также учебник для асинхронной обработки ввода-вывода на следующей странице.

Ответ №1

Предлагаемые ответы показывают, что в Boost есть инструменты, которые помогут вам в этом. Мое последнее предложение показывает, как использовать setitimer(), который является средством POSIX для итерационных таймеров.

Вам в основном нужны такие изменения:

while (1){ // wait until 200 ms boundary // get a sample }

С помощью итерационного таймера, обдуваемый сигнал прерывает любой заблокированный сигнал. Таким образом, вы могли бы просто заблокировать что-то навсегда. select сделает все для этого:

while (1){ int select_result = select(0, 0, 0, 0, 0); assert(select_result < 0 && errno == EINTR); // get a sample }

Чтобы установить таймер интервала на каждые 200 мс, используйте setitimer(), пройдя соответствующий интервал. В приведенном ниже коде мы устанавливаем интервал на 200 мс, где первый из них запускает 150 мс.

struct itimerval it = { { 0, 200000 }, { 0, 150000 } }; if (setitimer(ITIMER_REAL, &it, 0) != 0) { perror(«setitimer»); exit(EXIT_FAILURE); }

Теперь вам просто нужно установить обработчик сигнала для SIGALRM, который ничего не делает, и код завершен.

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

Если во время выполнения программы можно запускать несколько сигналов, вместо того чтобы полагаться на прерванный системный вызов, лучше блокировать то, что обработчик SIGALRM может просыпаться детерминированным способом. Одна из возможностей состоит в том, чтобы петля цикла while на read считываемого конца трубы. Обработчик сигнала может затем записать в конец записи этого канала.

void sigalarm_handler (int) { if (write(alarm_pipe[1], «», 1) != 1) { char msg[] = «write: failed from sigalarm_handlern»; write(2, msg, sizeof(msg)-1); abort(); } }

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

Ответ №2

Простое и точное решение с std::this_thread::sleep_until:

#include «chrono_io.h» #include «date.h» #include <chrono> #include <iostream> #include <thread> int main() { using namespace std::chrono; using namespace date; auto next = steady_clock::now(); auto prev = next — 200ms; while (true) { // do stuff auto now = steady_clock::now(); std::cout << round<milliseconds>(now — prev) << ‘n’; prev = now; // delay until time to iterate again next += 200ms; std::this_thread::sleep_until(next); } }

«chrono_io.h» и «date.h» не нужны для части задержки. Они предназначены для предоставления функции round<duration> (которая теперь находится на С++ 17) и облегчения печати duration s. Все это находится под “do stuff” и не имеет значения для задержки цикла.

Просто получите chrono::time_point, добавьте к нему задержку и спать до этого time_point. Ваша петля будет в среднем оставаться верной вашей задержке, если ваш “материал” занимает меньше времени, чем ваша задержка. Никакой другой темы не требуется. Не требуется таймер. Просто <chrono> и sleep_until.

Этот пример просто выводит для меня:

200ms 205ms 200ms 195ms 205ms 198ms 202ms 199ms 196ms 203ms … Ответ №3

Получить абсолютное восприятие будет практически невозможно – возможно, во встроенных системах. Однако, если вам требуется только приблизительная частота, вы можете получить довольно приличную производительность с помощью библиотеки хроно, например std::chrono (С++ 11) или boost::chrono. Например:

while (1){ system_clock::time_point now = system_clock::now(); auto duration = now.time_since_epoch(); auto start_millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count(); //run sample now = system_clock::now(); duration = now.time_since_epoch(); auto end_millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count(); auto sleep_for = max(0, 200 — (end_millis — start_millis )); std::this_thread::sleep_for( sleep_for ); } Ответ №4#include <thread> #include <chrono> #include <iostream> int main() { std::thread timer_thread; while (true) { timer_thread = std::thread([](){ std::this_thread::sleep_for (std::chrono::seconds(1)); }); // do stuff std::cout << «Hello World!» << std::endl; // waits until thread has «slept» timer_thread.join(); // will loop every second unless the stuff takes longer than that. } return 0; }

Оцените статью
Добавить комментарий