【发布时间】:2015-11-16 02:30:15
【问题描述】:
我已经编写了一个与TomTom GPS watches over Bluetooth 对话的实用程序,并试图让它作为一个运行后忘记的后台守护程序运行良好。
程序定期与 GPS 设备通信,然后sleeps 一段时间,直到再次需要它。
我注意到sleep() 与系统挂起的交互很奇怪:当我进入系统挂起(运行 Linux 3.16.0 内核的笔记本电脑)然后重新唤醒计算机时,sleep 似乎没有注意到挂起时间。比如下面的sleep.c:
#include <time.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char**argv)
{
time_t t=time(NULL);
printf("sleep at: %s", ctime(&t));
sleep(atoi(argv[1]));
t=time(NULL);
printf("wake at: %s", ctime(&t));
}
dlenski@dlenski-ultra:~$
编译、运行、中途休眠;
$ gcc sleep.c -o sleep
$ ./sleep 30
sleep at: Fri Aug 21 21:05:36 2015
<suspend computer for 17 seconds>
wake at: Fri Aug 21 21:06:23 2015
是否有一种正确的方法可以以时钟时间感知而不是系统正常运行时间的方式暂停程序执行-知道吗?
(我也试过usleep、nanosleep和alarm,发现它们的行为相似。)
更新:setitimer,正如@HuStmpHrrr 所建议的那样,听起来很有希望……但似乎也有同样的问题。
当我在它中间暂停时,这个版本会暂停超过请求的 30 秒...
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
void sighandler() {}
int main(int argc, char**argv)
{
time_t t=time(NULL);
printf("sleep at: %s", ctime(&t));
signal(SIGALRM, sighandler);
struct itimerval timer = {.it_interval={0,0},
.it_value={atoi(argv[1]),0}};
setitimer(ITIMER_REAL, &timer, NULL);
pause();
t=time(NULL);
printf("wake at: %s", ctime(&t));
}
【问题讨论】:
-
setitimer提供更多控制。你可以传入ITIMER_REAL来实现你想要的。 -
我不知道,经过短暂的搜索,我怀疑最可靠的方法是向电源管理系统注册,以便在暂停/恢复时收到通知。然后你只需要在恢复时检查你的定时器(除非你想让它们从挂起状态唤醒系统,这更难)。
-
对于 Linux,可能值得一看
pselect。您可以为定期返回设置超时,等待文件(描述符)活动等“有趣”事件以及信号事件。即使您认为现在不需要所有这些功能 - 您会获得更灵活的解决方案 - 而且您的实用程序看起来很有趣,您将来会需要更多功能和更好的响应时间。 -
为什么不使用
timer_create(CLOCK_MONOTONIC,..),并使用timer_settime(...,TIMER_ABSTIME,...)以绝对时间设置下一个到期时间? (甚至CLOCK_REALTIME,真的。)如果定时器在挂起期间过期,那么这样的定时器应该在唤醒后立即过期。这些也是 POSIX.1,因此也不需要特定于 Linux/桌面环境的恶作剧。 -
@DanLenski:注意
CLOCK_MONOTONIC永远不会被调整,它的零纪元是任意的,否则它类似于CLOCK_REALTIME;这就是为什么你引用的段落不适用于它。因为它从来没有调整过。但是,我还没有验证CLOCK_MONOTONIC在挂起期间进行,并且两种计时器都会在恢复后立即触发,所以这就是我在评论中使用条件的原因。你验证了它,你回答了它。 :)
标签: c linux sleep clock suspend