我正在写一个检查点。每次运行循环时我都会检查。我认为这会浪费大量的 CPU 时间。我想知道如何每 10 秒检查一次系统时间?
time_t start = clock();
while(forever)
{
if(difftime(clock(),start)/CLOCKS_PER_SEC >=timeLimit)
{
break;
}
}
非常简短的回答是,如果您是新手程序员,这非常困难。
现在有几个可能性:
睡十秒钟。这意味着您的程序基本上没有意义。
使用alarm()
和信号处理程序。这很难做到正确,因为您不能在信号处理程序中做任何花哨的事情。
使用 atimerfd
并将时序逻辑集成到您的 I/O 循环中。
为定时器设置一个专用线程(然后可以休眠);这非常困难,因为您需要考虑同步所有共享数据访问。
这里要带回家的一点是,您的问题没有简单的解决方案。您需要将时序逻辑深入集成到您现有的程序流程中。该流程应该是某种“主循环”(例如,像epoll_wait
or的 I/O 多路复用循环select
),可能是多线程的,并且该循环应该获取计时器已触发的事实。
那并没那么简单。
这是一个切线,可能具有指导意义。基本上有两种计算机程序(除了所有其他类型):
一种是尽可能高效地执行一项特定任务然后完成的程序。例如,这类似于“生成 SSL 密钥对”或“查找文件中与 X 匹配的所有行”。就程序流程而言,这些是易于编写和理解的程序。
另一种是与用户交互的程序。这些程序无限期地停留并响应用户输入。(基本上任何类型的 UI 或游戏,但也包括 Web 服务器。)从控制流的角度来看,这些程序大部分时间都在做......什么都不做。他们只是空闲等待用户输入。因此,当您考虑如何对此进行编程时,如何使程序什么都不做?这是“主循环”的核心:它是一个循环,它告诉操作系统让进程保持睡眠状态,直到发生有趣的事情,然后处理有趣的事件,然后重新进入睡眠状态。
直到您了解如何什么都不做,您才能设计第二种程序。
如果您需要精度,您可以使用 null 参数调用 select() 但有延迟。这精确到毫秒。
struct timeval timeout= {10, 0};
select(1,NULL,NULL,NULL, &timeout);
如果你不这样做,只需使用 sleep():
sleep(10);
最简单的方法(在单线程环境中)是休眠一段时间并反复检查总等待时间是否已过期。
int sleepPeriodMs = 500;
time_t start = clock();
while(forever)
{
while(difftime(clock(),start)/CLOCKS_PER_SEC <timeLimit) // NOTE: Change of logic here!
{
sleep(sleepPeriod);
}
}
请注意,这sleep()
不是很准确。如果您需要更高精度的计时(即分辨率优于 10 毫秒),您可能需要更深入地挖掘。此外,对于 C++11,还有<chrono>
提供更多功能的标头。
using namespace std::chrono;
int sleepPeriodMs = 500;
time_t start = clock();
while(forever)
{
auto start = system_clock()::now()
// do some stuff that takes between [0..10[ seconds
std::this_thread::sleep_until(start+seconds(10));
}
您可以在程序中使用事件循环并安排计时器进行回调。例如,您可以使用libev制作事件循环并添加计时器。
ev_timer_init (timer, callback, 0., 5.);
ev_timer_again (loop, timer);
...
timer->again = 17.;
ev_timer_again (loop, timer);
...
timer->again = 10.;
ev_timer_again (loop, timer);
如果您在特定工具包中编写代码,则可以使用其他事件循环,gtk、qt、glib 有自己的事件循环,因此您可以使用它们。
只需添加一个sleep调用即可为系统提供 CPU 时间:
time_t start = clock();
while(forever)
{
if(difftime(clock(),start)/CLOCKS_PER_SEC >=timeLimit)
{
break;
}
sleep(1); // <<< put process to sleep for 1s
}