统一调节程序执行率 [视窗C++]
Uniformly Regulating Program Execution Rate [Windows C++]
首先,我找到了很多关于这个主题的信息,但不幸的是,没有解决问题的解决方案。
我只是试图将我的C++程序调节为每秒 60 次迭代运行。我已经尝试了从GetClockTicks((到GetLocalTime((的所有方法来帮助监管,但是每次我在Windows Server 2008机器上运行该程序时,它的运行速度都比在本地机器上慢,我不知道为什么!
我知道基于"时钟"的函数调用返回执行时花费的 CPU 时间,所以我去了 GetLocalTime,然后尝试区分开始时间和停止时间,然后调用 Sleep((FPS/1000( - 毫秒执行时间(
我的本地机器比服务器CPU快得多,所以很明显,人们的想法是它正在关闭CPU时钟周期,但这并不能解释为什么GetLocalTime不起作用。我一直在基于 http://www.lazyfoo.net/SDL_tutorials/lesson14/index.php 更改 get_ticks(( 的方法,并返回我可以在网络上找到的所有函数。
例如,采用以下代码:
#include <Windows.h>
#include <time.h>
#include <string>
#include <iostream>
using namespace std;
int main() {
int tFps = 60;
int counter = 0;
SYSTEMTIME gStart, gEnd, start_time, end_time;
GetLocalTime( &gStart );
bool done = false;
while(!done) {
GetLocalTime( &start_time );
Sleep(10);
counter++;
GetLocalTime( &end_time );
int startTimeMilli = (start_time.wSecond * 1000 + start_time.wMilliseconds);
int endTimeMilli = (end_time.wSecond * 1000 + end_time.wMilliseconds);
int time_to_sleep = (1000 / tFps) - (endTimeMilli - startTimeMilli);
if (counter > 240)
done = true;
if (time_to_sleep > 0)
Sleep(time_to_sleep);
}
GetLocalTime( &gEnd );
cout << "Total Time: " << (gEnd.wSecond*1000 + gEnd.wMilliseconds) - (gStart.wSecond*1000 + gStart.wMilliseconds) << endl;
cin.get();
}
对于此代码片段,在我的计算机 (3.06 GHz( 上运行,我得到的总时间 (ms( 为 3856,而在我的服务器 (2.53 GHz( 上,我得到 6256。因此,尽管 2.53/3.06 的比率仅为 .826797386,而 3856/6271 的比率为 .614893956,但它可能是处理器的速度。
我无法判断 Sleep 函数是否正在做与预期截然不同的事情,尽管我不明白为什么会这样,或者这是否是我获取时间的方法(即使它应该是世界时间 (ms( 而不是时钟周期时间。任何帮助将不胜感激,谢谢。
首先,Sleep 的默认分辨率是计算机的配额长度 - 通常为 10 毫秒或 15 毫秒,具体取决于 Windows 版本。要获得 1ms 的分辨率,您必须发出 timeBeginPeriod(1(,它将计时器硬件重新编程为每毫秒(大约(触发一次。
在你的主循环中,你可以
int main()
{
// Timers
LONGLONG curTime = NULL;
LONGLONG nextTime = NULL;
Timers::GameClock::GetInstance()->GetTime(&nextTime);
while (true) {
Timers::GameClock::GetInstance()->GetTime(&curTime);
if ( curTime > nextTime && loops <= MAX_FRAMESKIP ) {
nextTime += Timers::GameClock::GetInstance()->timeCount;
// Business logic goes here and occurr based on the specified framerate
}
}
}
使用此时间库
include "stdafx.h"
LONGLONG cacheTime;
Timers::SWGameClock* Timers::SWGameClock::pInstance = NULL;
Timers::SWGameClock* Timers::SWGameClock::GetInstance ( ) {
if (pInstance == NULL) {
pInstance = new SWGameClock();
}
return pInstance;
}
Timers::SWGameClock::SWGameClock(void) {
this->Initialize ( );
}
void Timers::SWGameClock::GetTime ( LONGLONG * t ) {
// Use timeGetTime() if queryperformancecounter is not supported
if (!QueryPerformanceCounter( (LARGE_INTEGER *) t)) {
*t = timeGetTime();
}
cacheTime = *t;
}
LONGLONG Timers::SWGameClock::GetTimeElapsed ( void ) {
LONGLONG t;
// Use timeGetTime() if queryperformancecounter is not supported
if (!QueryPerformanceCounter( (LARGE_INTEGER *) &t )) {
t = timeGetTime();
}
return (t - cacheTime);
}
void Timers::SWGameClock::Initialize ( void ) {
if ( !QueryPerformanceFrequency((LARGE_INTEGER *) &this->frequency) ) {
this->frequency = 1000; // 1000ms to one second
}
this->timeCount = DWORD(this->frequency / TICKS_PER_SECOND);
}
Timers::SWGameClock::~SWGameClock(void)
{
}
带有包含以下内容的头文件:
// Required for rendering stuff on time
#pragma once
#define TICKS_PER_SECOND 60
#define MAX_FRAMESKIP 5
namespace Timers {
class SWGameClock
{
public:
static SWGameClock* GetInstance();
void Initialize ( void );
DWORD timeCount;
void GetTime ( LONGLONG* t );
LONGLONG GetTimeElapsed ( void );
LONGLONG frequency;
~SWGameClock(void);
protected:
SWGameClock(void);
private:
static SWGameClock* pInstance;
}; // SWGameClock
} // Timers
这将确保您的代码以 60FPS(或您输入的任何内容(运行,尽管您可能会转储MAX_FRAMESKIP因为在此示例中没有真正实现!
您可以尝试使用 WinMain
函数并使用 SetTimer
函数和常规消息循环(您还可以利用 GetMessage( ... )
的过滤机制(,其中您可以使用请求的时间测试WM_TIMER
消息,当计数器达到限制时,执行PostQuitMessage(0)
终止消息循环。
对于如此快的占空比,您可以使用高精度计时器(如 QueryPerformanceTimer(和忙碌等待循环。
如果你的占空比要低得多,但仍然想要精度,那么你可以睡一部分时间,然后用忙碌的等待循环来消耗剩余的时间。
另一种选择是使用类似DirectX的东西将自己同步到VSync中断(几乎总是60 Hz(。 如果您正在编写游戏或 A/V 演示文稿,这可能很有意义。
Windows不是一个实时操作系统,所以永远不会有完美的方法来做这样的事情,因为不能保证你的线程会被安排在你需要的时候运行。
请注意,在 Sleep 的备注中,实际时间量将至少是一个"滴答",并且可能比您在计划线程再次运行之前请求的延迟长一个完整的"滴答"(然后我们必须假设线程已调度(。 "勾号"可能会有很大差异,具体取决于硬件和Windows版本。 它通常在 10-15 毫秒的范围内,我见过它和 19 毫秒一样糟糕。 对于 60 Hz,每次迭代需要 16.666 毫秒,因此这显然不够精确,无法满足您的需求。
根据每帧渲染之间经过的时间进行渲染(迭代(怎么样?考虑创建一个void render(double timePassed)
函数并根据timePassed
参数进行呈现,而不是让程序进入睡眠状态。
例如,想象一下,你想渲染一个球掉落或弹跳。你会知道它是速度,加速度和你需要的所有其他物理。根据timePassed
和所有其他物理参数(速度、加速度等(计算球的位置。
或者,如果您愿意,如果经过的时间值很小,则可以跳过render()
函数执行,而不是将程序置于睡眠状态。
- 视窗键盘输入 c++
- 视窗 10 :笔(手写笔)在 MFC 应用程序上不起作用
- C++标准视窗 SDK 文件中的编译错误
- 无法为 AES 加密创建 contex.视窗XP
- 检查视窗版本
- QtCreator 不构建.(视窗)
- 视窗 7 访问冲突
- 如何伪造键盘换档按.Qt,视窗10
- 加载的 OpenGL 函数是特定于上下文还是特定于线程?(视窗)
- 视窗驱动程序IOCTL代码蓝屏/使计算机崩溃
- 视窗驱动程序,旋转锁采集和条件测试
- 皮克西 ||C++ ||视窗 10.
- 如何获取 winMain 的 hInstance?视窗32编程
- C++/CX 中的 [这] 是什么?(视窗 8)
- C++ - 视窗 - BIOS 序列号 - 如何获取
- 视窗地图文件系统
- 视窗 8 拼写检查提供程序
- 在视窗/C++中强制显示分辨率
- C++/视窗 - 含义: 系统( "dir \b *.dat > tmp.txt" )
- 视窗fnmatch替代品