在C ++代码中设置while循环的执行速率以进行实时同步

时间:2013-02-18 20:49:46

标签: c++ synchronization while-loop

我正在使用.cpp源代码进行实时模拟。我必须每0.2秒采样一次( 200 ms )...有一个while循环每次采取一个样本...我想同步这个while循环的执行来获取每个样本( 200 ms )...我应该如何修改while循环?

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

5 个答案:

答案 0 :(得分: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" and "date.h"。他们在那里提供round<duration>函数(现在在C ++ 17中),并且可以更容易地打印出duration。这一切都在&#34;做东西&#34;,并且对于循环延迟并不重要。

只需获得chrono::time_point,将延迟添加到其中,然后一直睡到time_point。只要你的&#34;东西&#34;你的循环将平均保持你的延迟。花费的时间比延迟时间短。不需要其他线程。无需计时器。只需<chrono>sleep_until

这个例子只为我输出:

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

答案 1 :(得分:1)

除非你使用的是实时操作系统,否则你所要求的是棘手的。

但是,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 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 to boost 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;
}

还有一个教程,用于在下一页上异步处理IO。

答案 2 :(得分: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 ms建立一个间隔计时器,请使用setitimer(),并以适当的间隔传递。在下面的代码中,我们设置一个200毫秒的间隔,其中第一个间隔从现在开始150毫秒。

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

现在,您只需为SIGALRM安装一个什么都不做的信号处理程序,代码就完成了。

您可以点击此链接查看the completed example

如果在程序执行期间可能触发多个信号,那么最好不要依赖于SIGALRM处理程序以确定的方式唤醒的内容,而不是依赖于中断的系统调用。 。一种可能性是在管道读取端的while上有read循环块。然后,信号处理程序可以写入该管道的写端。

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

点击链接查看the completed example

答案 3 :(得分:1)

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

答案 4 :(得分:0)

获得绝对精确度几乎是不可能的 - 可能在嵌入式系统中。但是,如果您只需要一个近似频率,那么使用std::chrono(c ++ 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 );
}