C++ std::this_thread::sleep_,直到计时完全停止大约2倍,这是令人费解的
好吧,我真的不知道为什么会这样。我目前正在实现一个线程容器,它以分离的方式运行一个无限循环,在每次迭代之间限制一定的速度 标题:C++ std::this_thread::sleep_,直到计时完全停止大约2倍,这是令人费解的,c++,stl,sleep,C++,Stl,Sleep,好吧,我真的不知道为什么会这样。我目前正在实现一个线程容器,它以分离的方式运行一个无限循环,在每次迭代之间限制一定的速度 标题: class timeloop { public: std::thread thread = { }; bool state = true; void (*function_pointer)() = nullptr; double ratio = 1.0f; std::chrono::nanoseconds elapsed =
class timeloop
{
public:
std::thread thread = { };
bool state = true;
void (*function_pointer)() = nullptr;
double ratio = 1.0f;
std::chrono::nanoseconds elapsed = { };
timeloop(
void (*function_pointer)() = nullptr
);
void function();
};
定义:
void timeloop::start()
{
this->thread = std::thread(
&loop::function,
this
);
}
void timeloop::function()
{
std::chrono::steady_clock::time_point next;
std::chrono::steady_clock::time_point start;
std::chrono::steady_clock::time_point end;
while (
this->state
)
{
start = std::chrono::high_resolution_clock::now();
next = start + std::chrono::nanoseconds(
(long long) (this->ratio * (double) std::chrono::nanoseconds::period::den)
);
if (
this->function_pointer != nullptr
)
{
this->function_pointer();
}
/***************************
this is the culprit
***************************/
std::this_thread::sleep_until(
next
);
end = std::chrono::high_resolution_clock::now();
this->elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(
end - start
);
}
}
定义代码的行为异常,特别是std::this_thread::sleep_until
。由于this->ratio=1.0/128.0
我预计帧率约为128,因此start
和next
的计算值强化了这一点,但它莫名其妙地徘徊在60左右。是的,我试着把next
除以2,但实际上它降到了40左右
验证正常睡眠时间的额外代码:
auto diff = std::chrono::nanoseconds(
next - start
).count() / (double) std::chrono::nanoseconds::period::den;
auto equal = diff == this->ratio;
其中equal的计算结果为true
帧速率计算:
double time = (double) thread_draw->elapsed.count() / (double) std::chrono::nanoseconds::period::den;
double fps = 1.0 / time;
虽然我也使用了外部FPS计数器进行验证(NVIDIA ShadowPlay和RivaTuner/MSI加力),但它们在计算值的+-5范围内
我知道它是std::this_thread::sleep_,直到,因为一旦我把它注释掉,帧速率就会跳到2000左右。嗯
我真的很困惑,尤其是看到我怎么找不到任何其他人有过这个问题的证据。是的,我知道睡眠功能并不完全准确,偶尔也会打嗝,但持续的睡眠时间几乎是预定时间的两倍是荒谬的
我是否误解了编译器选项或其他什么?这绝对不是一个性能问题,我也有理由相信这也不是一个逻辑错误(看看所有计算的结果如何)[除非我在某个地方滥用了chrono]。没有关于
睡眠的解决方案的保证,直到
,你只能保证线程不会在时间点之前被唤醒。如果您正在实现主游戏循环,请阅读
用睡眠来保证时间是一种可怕的方法。你受操作系统调度程序的支配,例如,我相信Windows的最小睡眠时间大约为10毫秒。(如果实现实际上要求操作系统将线程置于睡眠状态,并且操作系统决定进行上下文切换。)
如果调用glfwSwapBuffers
或类似命令,则延迟也可能由绘图线程中的VSync引起。这就解释了为什么你的睡眠时间被限制在60FPS,而不是为什么评论sleep
可以解决这个问题
我猜上面是操作系统的睡眠。我建议你取消睡眠,使用VSync,这是你想要的正确频率。与逻辑线程同步将是一个痛苦的。。。但情况总是这样。我想你的问题是你没有使用绝对计时,因为你一直在重置绝对时间点
next
相对于当前时间now()
尝试更改此选项:
while (
this->state
)
{
start = std::chrono::high_resolution_clock::now();
next = start + std::chrono::nanoseconds(
(long long) (this->ratio * (double) std::chrono::nanoseconds::period::den)
);
// ...
对此
// before the loop
next = std::chrono::high_resolution_clock::now();
while (
this->state
)
{
// keep the timing absolute by adding to the absolute time point
next = next + std::chrono::nanoseconds(
(long long) (this->ratio * (double) std::chrono::nanoseconds::period::den)
);
// ...
这样,您只需调用一次now()
,随后的所有计时都是从该点开始计算的(与相对计时相反)
编辑以添加:
此外,我将避免使用std::chrono::high_resolution_clock
。它通常只是std::chrono::system_clock的别名,当系统时钟试图与internet时间保持同步时,它会受到随机时间更改的影响
使用
std::chrono::staid_clock
这真的很奇怪,因为我在不同的项目中使用了基本相同的代码,而且工作得非常好。也在同一台机器上。绝对没有10毫秒的最小延迟,这是当场,即使在目标更高的帧速率(如200+)。不管怎样,我从那篇文章中收集到的信息基本上是使用while循环,只做操作系统基本上自己做的事情(即使稍微贵一点)。@TARN4T1ON不确定,那么你可以试着做一个简单的程序,睡在主屏幕上,看看你能得到的最小数量是多少。是的,这篇文章更倾向于物理,但对于与时间相关的循环,它是一个很好的建议。它不使用睡眠,正是因为它不可靠。我实际上看了一下我第一次使用这种代码的项目,它在那里也不再工作了。这方面的建设也滞后。真的很时髦。老实说,可能是最近的一些更新,其他一些东西对我来说也不起作用了(比如VisualStudio的Performance Profiler,我其实想用它来了解这一点,但是是的…)。我只使用while循环。谢谢是的优质chrono实现。通过设置与调用now()
相关的next
点,每次您失去绝对时间给您的任何优势时。也许这会有帮助:这就是它过去的工作方式,遗憾的是它没有什么不同。而且,这可能会落后太多(如果主函数花费太多太多时间,或者可能是整个时间),在这一点上,它甚至不会限制任何东西。@TARN4T1ON在我看来,如果你想要定期计时,那么你想在这段时间内做的工作必须是可行的。如果主函数花费的时间太长,那么你就无能为力,因为你的基本问题是主函数花费的时间太长。。。但是不管怎样,你现在做的方式将不可避免地漂移,因为它没有固定在一个绝对的时间基础上。@TARN4T1ON我还添加了一个关于std::chrono::high_resolution_clock
的注释。你应该使用std::chrono::staid_clock你说得对,我在试错阶段更改了它,但没有更改回来。但似乎睡眠比我记忆中的要糟糕得多(尽管我可以发誓几个月前它还不错)。谢谢你的帮助。
// before the loop
next = std::chrono::high_resolution_clock::now();
while (
this->state
)
{
// keep the timing absolute by adding to the absolute time point
next = next + std::chrono::nanoseconds(
(long long) (this->ratio * (double) std::chrono::nanoseconds::period::den)
);
// ...