【问题标题】:Is Increment Speed Affected By Clock Rate增量速度是否受时钟速率影响
【发布时间】:2021-08-24 01:03:23
【问题描述】:

考虑下面的循环。这是我试图解决的问题的简化示例。我想限制每秒调用 doSomething 函数的次数。由于循环工作得非常快,我想我可以使用速率限制器。假设我通过使用不同的 x 数字运行它找到了合适的值。

unsigned int incrementionRate = x;
unsigned int counter == 0;

while (true) {

    double seconds = getElapsedSeconds();
    print(seconds);

    counter = (counter + 1) % incrementionRate;
    if (counter == 0) {
        doSomething();
    }
}

我想知道如果我使用较低的时钟频率,调用 doSomething 函数的次数是否会减少。在这种情况下,我想将调用 doSomething 函数的次数限制为每秒一次。我写的第二个循环如下。

float epsilon = 0.0001;
while (true) {

    double seconds = getElapsedSeconds();
    print(seconds);

    if (abs(seconds - floor(seconds)) <= epsilon) {
        doSomething();
    }
}

这对不同的时钟周期有用还是仍然存在问题?另外,我想知道是否有更好的方法来做到这一点。我以前从未使用过时钟频率,并试图了解在使用有限资源时关注点有何不同。

注意:不能使用睡眠。

【问题讨论】:

  • 我宁愿将秒除以次数以获得具体的偏移量,然后 sleep until 下一个周期过去了。
  • getElapsedSecondsprint 是什么?我不明白这两个代码如何每秒调用一次doSomething。首先,经过的时间和对doSomething 的调用之间似乎没有(准确的)关系,因为它只计算循环迭代
  • 这个while 循环的其余部分是否应该继续循环,并且每秒只调用一次doSomething() - 或者睡觉可以吗?
  • 第二个循环只能在裸机/实时操作系统上工作,如果你在这种情况下,你可以使用定时器中断。在一般情况下,您不能保证 getElapsedSeconds() 将在“espsilon”tiemspan 内被调用,因此您会错过一帧。对此没有平台无关的解决方案。
  • 您能否提供有关您将使用的平台的详细信息?为什么睡眠不是一种选择?

标签: c++ clockrates


【解决方案1】:

如果我对这个问题理解得比较透彻,您可以使用 std::chrono::steady_clock,每经过一秒就添加一秒。

例子:

#include <chrono>

auto end_time = std::chrono::steady_clock::now();

while (true) {
    // only call doSomething once a second
    if(end_time < std::chrono::steady_clock::now()) {
        doSomething();
        // set a new end time a second after the previous one
        end_time += std::chrono::seconds(1);
    }

    // do something else
}

【讨论】:

    【解决方案2】:

    Ted's answer 可以真的在循环中做其他事情;但是,如果 not,这会导致忙碌的等待,这只会白白消耗你的 CPU。

    在这种情况下,您宁愿让线程休眠:

        std::chrono::milliseconds offset(200);
        auto next = std::chrono::steady_clock::now();
        for(;;)
        {
            doSomething();
            next += offset;
            std::this_thread::sleep_until(next);
        }
    

    您需要包含 chronothread 标头。

    【讨论】:

    • 这太相信睡眠的精确性了;如果您完全关心精度,请在活动前睡到 10 毫秒,然后旋转。但是,我喜欢它没有错误累积。
    • @Yakk-AdamNevraumont 我没有假设如此高的精度要求,正如问题中没有提到的那样。使用典型的多线程操作系统和 10 ms 或类似的时间片,即使使用 100 us 时间缓冲区,我们也可能无法实现它。具有高精度振荡器和定时器中断的微控制器可能是更好的选择。但是随着问题的编辑排除了这个解决方案,答案无论如何都已经过时了......它可能对其他读者仍然有用,所以我不会删除它。
    【解决方案3】:

    最后我决定采用更简单的方法。使用可调整的时间间隔,只存储最新的更新时间,没有引入任何新机制。老实说,现在我不知道为什么我一开始想不到。过度思考是个问题。 :)

    double lastUpdateTimestamp = 0;
    const double updateInterval = 1.0;
    
    while (true) {
    
        double seconds = getElapsedSeconds();
        print(seconds);
    
        if ((elapsedSeconds - lastUpdateTimestamp) >= updateInterval) {
            doSomething();
            lastUpdateTimestamp = elapsedSeconds;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-06-30
      • 1970-01-01
      • 2021-08-16
      • 1970-01-01
      • 1970-01-01
      • 2022-10-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多