1

在 C++ 中尽可能接近 30 毫秒退出循环的最佳方法是什么。轮询提升:microsec_clock ?轮询 QTime ?还有什么?

就像是:

A = now;
for (blah; blah; blah) {
    Blah();
    if (now - A > 30000)
         break;
}

它应该可以在 Linux、OS X 和 Windows 上运行。

循环中的计算用于更新模拟。每 30 毫秒,我想更新视口。

4

9 回答 9

11

循环中的计算用于更新模拟。每 30 毫秒,我想更新视口。

您是否考虑过使用线程?您所描述的似乎是为什么您应该使用线程而不是计时器的完美示例。

主进程线程继续处理 UI,并将 QTimer 设置为 30ms 来更新它。它锁定QMutex以访问数据、执行更新并释放互斥锁。

第二个线程(参见QThread)进行模拟。对于每个周期,它会锁定 QMutex,进行计算并在数据处于稳定状态时释放 mutex(适用于 UI 更新)。

随着多核处理器的增长趋势,您应该越来越多地考虑使用线程而不是使用计时器。您的应用程序会自动受益于新处理器增加的功率(多核)。

于 2009-06-03T19:21:46.880 回答
4

虽然这不能回答问题,但它可能会重新审视解决方案。将模拟代码和用户界面放在不同的线程中怎么样?如果您使用 Qt,则可以使用计时器甚至QThread::msleep()来实现定期更新。您可以调整螺纹 Mandelbrot 示例以满足您的需要。

于 2009-06-03T19:47:43.737 回答
2

此链接中的代码片段示例几乎可以满足您的要求:

http://www.cplusplus.com/reference/clibrary/ctime/clock/

改编自他们的例子:

void runwait ( int seconds )
{
   clock_t endwait;
   endwait = clock () + seconds * CLOCKS_PER_SEC ;
   while (clock() < endwait)
   {
      /* Do stuff while waiting */
   }
}
于 2009-06-03T18:00:14.720 回答
2

简短的回答是:通常不能,但如果您在正确的操作系统或正确的硬件上运行,则可以。

您可以在所有操作系统上使用英特尔系统上的程序集调用和其他架构上的其他东西来获得接近 30 毫秒的时间。当我找到它时,我会挖掘参考并编辑答案以包含代码。

问题在于时间片算法以及您在多任务操作系统上的时间片结束有多近。

在某些实时操作系统上,您可以在系统库中进行系统调用,但我不确定该调用是什么。

编辑:大声笑!有人已经在 SO 上发布了一个类似的片段: Timer function to provide time in nano seconds using C++

VonC 得到了带有 CPU 定时器汇编代码的注释。

于 2009-06-03T18:07:34.500 回答
2

如果您需要在经过一定时间之前完成工作,那么docflabby 的答案就是正确的。但是,如果您只需要等待,什么都不做,直到经过指定的时间,那么您应该使用usleep()

于 2009-06-03T18:08:07.683 回答
2

根据您的问题,您希望每 30 毫秒更新一次视口。我曾经写过一个类似的应用程序,它每 500 毫秒探测一次硬件以寻找类似的东西。虽然这不能直接回答您的问题,但我有以下跟进:

  • 您确定用于更新视口的 Blah() 在每个实例中都可以在不到 30 毫秒的时间内执行吗?
  • 似乎更像是通过计时器回调来运行 Blah() 会更好。
  • 很难找到一个库计时器对象,它会以 30 毫秒的间隔在图形框架中进行更新。在 Windows XP 上,我发现标准的 Win32 API 计时器在计时器间隔到期时推送窗口消息,即使在 2GHz P4 上,也无法以超过 300 毫秒的间隔进行更新,无论我将计时间隔设置为多低计时器。虽然 Win32 API 中提供了高性能计时器,但它们有很多限制,即您不能像上面提到的那样在循环中执行任何 IPC(如更新 UI 小部件)。
  • 基本上,结果是您必须非常仔细地计划您希望如何进行更新。您可能需要使用线程,并查看您希望如何更新视口。

只是有些事情要考虑。当我从事我的项目时,他们让我大吃一惊。如果您已经考虑过这些事情,请忽略我的回答:0)。

于 2009-06-03T18:47:12.627 回答
2

您可能会考虑每 N 个模拟步骤而不是每 K 毫秒更新一次视口。如果这是(比如说)一个严肃的商业应用程序,那么您可能会想要走其他地方建议的多线程路线,但如果(比如说)它是供个人或有限观众使用并且您真正感兴趣的是你正在模拟的任何东西的细节,那么每 N 步都很简单,可移植,并且可能足够好,可以继续使用。

于 2009-06-03T20:04:39.647 回答
0

请参阅 QueryPerformanceCounter 和 QueryPerformanceFrequency

于 2009-06-03T17:55:37.990 回答
0

如果您使用的是 Qt,这里有一个简单的方法来做到这一点:

QTimer* t = new QTimer( parent ) ;
t->setInterval( 30 ) ; // in msec
t->setSingleShot( false ) ;
connect( t, SIGNAL( timeout() ), viewPort, SLOT( redraw() ) ) ;

您需要指定viewPortredraw()。然后用 启动计时器t->start()

于 2009-06-03T19:04:13.653 回答