Setting the execution speed of a while loop in C ++ code for realtime synchronization

I am doing real time simulation using source code .cpp

. I have to take a sample every 0.2 seconds ( 200ms ) ... There is a while loop that takes a sample every time step ... I want to synchronize the execution of this while loop to get a sample every ( 200ms ) ... How should I change the while loop?

while (1){
          // get a sample every 200 ms
         }

      

+3


source to share


5 answers


what you are asking is difficult unless you are using a real time operating system.

However, Boost has a library that supports what you want. (However, there is no guarantee that you will be called exactly every 200ms.

The Boost ASIO library is probably exactly what you are looking for, here is the code from their tutorial:

//
// 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 http://www.boost.org/LICENSE_1_0.txt)
//

#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;
}

      



link here: link to increase asio .

You can take this code and rearrange it this way

#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;
}

      

There is also a tutorial for asynchronous I / O processing on the next page.

+1


source


The suggested answers show that Boost has tools to help you with this. My last suggestion shows how to use setitimer()

which is a POSIX facility for iterative timers.

You basically need changes like this:

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

      

With an iteration timer, the blown signal interrupts any blocked signal. That way, you could just block something forever. select

will do everything for this:

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

      

To set an interval timer every 200ms, use setitimer()

by going through the appropriate interval. In the code below, we are setting the interval to 200ms, where the first one starts 150ms.



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

      

Now you just need to install a signal handler for SIGALRM

that does nothing and the code is complete.

You can follow the link to see the completed example .

If multiple signals can be triggered during program execution, rather than relying on an interrupted system call, it is best to block that the handler SIGALRM

can wake up in a deterministic way. One possibility is to loop the loop while

at the read

read end of the pipe. The signal handler can then write to the end of that channel's record.

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

      

Follow the link to see the completed example .

+1


source


Simple and accurate solution with 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"

and"date.h"

not needed for part of the delay. They are meant to provide a function round<duration>

(which is now in C ++ 17) and make duration

s easier to print . It's all under the "do stuff" and doesn't matter for loop latency.

Just get it chrono::time_point

, add a delay to it and sleep before that time_point

. Your loop will, on average, stay true to your delay if your "stuff" takes less time than your delay. No other theme is required. No timer required. Simple <chrono>

and sleep_until

.

This example just outputs for me:

200ms
205ms
200ms
195ms
205ms
198ms
202ms
199ms
196ms
203ms
...

      

+1


source


Absolute perception will be nearly impossible - perhaps in embedded systems. However, if you only want an approximate frequency, you can get pretty decent performance with a chrono library like std::chrono

(C ++ 11) or boost::chrono

. For example:

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 );
}

      

0


source


#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;
}

      

0


source







All Articles