有两个主题。一个是事件线程,另一个是渲染。呈现线程使用事件线程中的变量。有互斥锁,但它们无关紧要,因为我注意到即使我完全删除它们(用于测试),行为也是一样的。
如果我单独在渲染线程中执行sleep(),持续10毫秒,则FPS通常为100。
如果我在渲染线程中没有睡眠并且在事件线程中睡眠,则渲染线程根本不会减慢。
但是,如果我在渲染线程中进行10毫秒的休眠,而在事件线程中进行10次睡眠,则FPS不是100,而是低,大约84! (注意,即使完全删除了互斥锁,它也是一样的)
(如果他们都没有睡觉,通常会变高。)
什么会产生这种行为?
-
使用的sleep命令是Windows的Sleep()或SDL_Delay()(可能在Windows上最终为Sleep())。
答案 0 :(得分:1)
我相信我找到了答案(自己的答案)。
不保证睡眠等待一段时间,但由于操作系统安排,它会等待至少一段时间。
更好的方法是计算明确传递的实际时间(并允许通过该方法执行,仅在特定时间过去时)。
答案 1 :(得分:0)
线程以异步方式运行,除非您同步它们,并将根据操作系统的调度策略进行调度。我建议这种行为最多只能是非确定性的(除非你是在RTOS上运行)。
你可能最好让一个线程通过一些同步机制(如信号量)触发另一个线程,然后只有一个线程Sleep,另一个线程等待信号量。
我不知道你的“事件”线程做了什么但是给出了它的名字,也许最好等待事件本身而不是简单地睡觉然后轮询事件(如果这就是它的作用)。使渲染定期进行可能是有意义的,但等待事件会更好地做到这一点。
答案 2 :(得分:0)
行为将根据许多因素而变化,例如操作系统版本(例如Win7与Win XP)和核心数量。如果你有两个核心和两个没有同步对象的线程,它们应该同时运行,一个线程上的Sleep()不应该影响另一个(大多数情况下)。
听起来你在线程之间有一些其他同步,因为否则当你在渲染线程中根本没有睡眠时,你应该以> 100FPS运行,不是吗?
如果绝对没有同步,那么根据具有它们的两个线程中发生了多少处理,Sleep()可能会增加单个核心系统争用的可能性。也就是说,如果只有一个线程调用Sleep(),它通常很可能在它唤醒后被给予下一个量子并且假设它执行非常少的处理,即立即产生,该行为将继续。如果两个线程正在调用Sleep(),则它们有可能在相同的量子中唤醒,并且如果它们中的至少一个需要进行任何处理,则另一个将被延迟并且观察到的频率将更低。这应该仅适用于可用于运行两个线程的单个核心。
如果要保持100FPS的更新速率,您应该跟踪下一个预定的更新时间,并且只剩下睡眠剩余时间。这将确保即使您的线程受到CPU量子的其他线程的影响,您也可以保持速率(假设所有处理都有足够的CPU时间)。类似的东西:
DWORD next_frame_time = GetTickCount(); // Milli-seconds. Note the resolution of GetTickCount()
while(1)
{
next_frame_time += 10; // Time of next frame update in ms
DWORD wait_for = next_frame_time - GetTickCount(); // How much time remains to next update
if( wait_for < 11 ) // A simplistic test for the case where we're already too late
{
Sleep(wait_for);
}
// Do periodic processing here
}
根据目标操作系统和精度要求,您可能需要使用更高分辨率的时间函数,例如QueryPerformanceCounter()。上面的代码在Windows XP上不能很好地工作,其中GetTickCount()的分辨率大约为16ms,但在Win7中应该可以工作 - 这主要是为了说明我的观点,而不是在所有情况下按字面意思复制。