我是靠谱客的博主 落寞野狼,最近开发中收集的这篇文章主要介绍linux 如何设置待机时间_Linux下的精确定时与休眠,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Linux中提供的休眠函数是sleep(),但是仅仅提供以秒为单位的休眠,这种休眠对有些进程显然太长了,那么怎样才能使进程以更小的时间分辨率休眠呢?

我知道的方法有2种,下面就做分别介绍。

第一种方法是使用定时器,Linux提供的定时器函数是:

int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);

which指定那种定时器。Linux提供3种定时器:

TIMER_REAL: 准确定时器,超时会发出SIGALRM信号;

TIMER_VIRTUAL: 虚拟定时器,只记进程时间,所以会根据进程执行时间而变化,不能实现准确定时,超时发出SIGVTALRM信号;

TIMER_PROF: 梗概计时器,它会根据进程时间和系统时间而变化,不能实现准确定时,超时发出SIGPROF信号;

在进程中应该捕捉所设定时器会发出的信号,因为进程收到定时器超时发出的信号后,默认动作是终止。

value是设置定时器时间,相关结构如下:

struct itimerval {

struct timeval it_interval;

struct timeval it_value;

};

struct timeval {

long tv_sec;

long tv_usec;

};

it_interval

指定间隔时间,it_value指定初始定时时间。如果只指定it_value,就是实现一次定时;如果同时指定it_interval,则超时后,系统

会重新初始化it_value为it_interval,实现重复定时;两者都清零,则会清除定时器。

tv_sec提供秒级精度,tv_usec提供微秒级精度,以值大的为先,注意1s = 1000000us。

ovalue用来保存先前的值,常设为NULL。

如果是以setitimer()提供的定时器来休眠,只需用pause()阻塞等待定时器信号就可以了。第二种方法是使用select()来提供精确定时和休眠:

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

n指监视的文件描述符范围,通常设为所要select()的fd+1,readfds,writefds和exceptfds分别是读,写和异常文件描述符集,timeout为超时时间。

可能用到的关于文件描述符集操作的宏有:

FD_CLR(int fd, fd_set *set); 清除fd

FD_ISSET(int fd, fd_set *set); 测试fd是否设置

FD_SET(int fd, fd_set *set); 设置fd

FD_ZERO(fd_set *set); 清空描述符集

我们此时用不到这些宏,因为我们并不关心文件描述符的状态,我们关心的是select()超时。所以我们需要把readfds,writefds和

exceptfds都设为NULL,只指定timeout时间就行了。至于n我们可以不关心,所以你可以把它设为任何非负值。实现代码如下:

int usSleep(long us) {

struct timeval tv;

tv.tv_sec = 0;

tv.tv_usec = us;

return select(0, NULL, NULL, NULL, &tv);

}

呵呵,怎么样,是不是很简单?

结语:

setitimer()

和select()都能实现进程的精确休眠,本文分别对他们进行了简单介绍,并给出了一个简单的基于select()的实现。我不推荐使用

setitimer,因为一者Linux系统提供的timer有限(每个进程至多能设3个不同类型的timer),再者setitimer()实现起来没

有select()简单。

编辑于2008年9月12日

-------------------------------------------------------------------

非常感谢33和ffff的反馈,ms与us的错误已经更正。由于小弟学艺不精,给大家造成的误解多原谅,另外也欢迎提出你的见解,我们一起交流进步。我已

经把标题改了,原来的标题已经不适合现在的内容,因为我想把其他sleep函数也添加进来。首先,就如ffff提出的那样,用usleep()可以实现进

程的秒以下休眠。

int usleep(unsigned long usec);

同sleep()一样,它在进程收到任何信号时都会返回。不过Linux手册上说,它并不会像sleep()一样会返回没休眠的秒数,而是返回-1,并把errno设为EINTR。 uClibc的实现如下:

int usleep (__useconds_t usec)

{

const struct timespec ts = {

.tv_sec = (long int) (usec / 1000000),

.tv_nsec = (long int) (usec % 1000000) * 1000ul

};

return(nanosleep(&ts, NULL));

}

可见usleep()内部是由nanosleep()函数实现的,接下来我们会讨论nanosleep()函数。我还见过如下用select()实现的,也支持了我前面所说的方法。

int usleep( unsigned long usec )

{

static struct { /* `timeval' */

long tv_sec; /* seconds */

long tv_usec; /* microsecs */

} delay; /* _select() timeout */

delay.tv_sec = usec / 1000000L;

delay.tv_usec = usec % 1000000L;

return select(0, (long *)0, (long *)0, (long *)0, &delay);

}

接下来我们再来看看nanosleep()。nanosleep()可以实现纳秒(1/1000 000 000)级的休眠,所以它比usleep()更精确。但是你的CPU至少要1GHz以上才能支持这么高的分辨率。nanosleep()的原型如下:

int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);

第一个参数指定要休眠的时间,第二个参数返回被信号中断时还没有休眠够的时间,timespec结构如下:

struct timespec {

time_t tv_sec; /* seconds */

long tv_nsec; /* nanoseconds */

};

tv_sev 用于指定秒数,tv_nsec用于指定纳秒数(0-999 999

999),注意不像前面所说的其它函数,nanosleep()对timespec结构的2个成员都要使用,所以你不能为tv_nsec指定大于999

999

999的数值,大于此数的应该送给tv_sec。所有的sleep函数遇信号都会返回,sleep()和alarm()遇信号返回剩余的时间,而

usleep(),nanosleep()和 select()遇信号都会返回-1。

最后

以上就是落寞野狼为你收集整理的linux 如何设置待机时间_Linux下的精确定时与休眠的全部内容,希望文章能够帮你解决linux 如何设置待机时间_Linux下的精确定时与休眠所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(38)

评论列表共有 0 条评论

立即
投稿
返回
顶部