志在指尖
用双手敲打未来

linux定时器的使用(示例)

linux定时器的使用

日常常用的几个守时器相关linuxAPI函数
init_timer();初始化守时器
add_timer();发动定制器
del_timer();中止守时器
mod_timer();重新修正守时器当时计数时刻
这些API坐落:kernel\timer.c中,该源文件里还包括了常用的msleep(),schedule_timeout()等常用的延时调度函数。
下面以一个实例驱动介绍linux里的timer的运用(根据3.10.0-123内核)。
事例如下:
创立一守时器,完成每3s一次周期性中止并打印。
经过字符设备接口与用户层交互,写0则封闭(中止)守时器,写1则敞开(发动)守时器
(即:当echo1>/dev/demo_deva发动守时器,当echo0>/dev/demo_deva中止守时器)。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include”timer_drv.h”
/*
功能:
守时器3秒守时中止一次打印。
当echo1>/dev/demo_deva敞开守时器,当echo0>/dev/demo_deva封闭守时器
*/
#defineDRV_VERSION”V1.0″
MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“LUDY”);
MODULE_DESCRIPTION(“Thisistimerdemo”);
MODULE_VERSION(DRV_VERSION);
//staticvolatileinttime_count=0;
staticvoidhandel_irq_do_timer(unsignedlongarg);
u8delay=3;//3s
/*设备要运用的守时器*/
staticstructtimer_listmy_timer;//也能够:TIMER_INITIALIZER(handel_irq_do_timer,0,0);直接快速初始化结构体内容
/*守时器中止处理函数*/
staticvoidhandel_irq_do_timer(unsignedlongarg)
{
//structxxx_device*dev=(structxxx_device*)(arg);
/*修正调度守时器,3s再履行*/
mod_timer(&my_timer,jiffies+delay*HZ);//*HZ即转换成jiffies单位值
printk(“timerarrival\n”);
}
/*守时器初始化*/
voidtimer_init_run(void*pri_data)
{
//device*dev=(device*)pri_data;
/*初始化守时器*/
init_timer(&my_timer);
/*设备结构体指针作为守时器处理函数参数*/
my_timer.function=&handel_irq_do_timer;//中止处理函数
my_timer.expires=delay*HZ;//守时时刻delay秒
//my_timer.data=(unsignedlong)dev;
}
/*
写函数;
守时器发动和中止操控
*/
ssize_tdemodrv_write(structfile*file,constchar__user*buf,size_tcount,loff_t*ppos)
{
charrev_data;
/*只接受一个字符的写入*/
if(count>2)//count包括了/0字符
return-EFAULT;
//copy_from_user(rev_data1,buf,count);
if(get_user(rev_data,buf))
{
return-EFAULT;
}
printk(“driver:devicewrite:%ccount:%d\n”,rev_data,count);
switch(rev_data)
{
case’0′:
/*删去(中止)守时器*/
del_timer(&my_timer);
break;
case’1′:
/*增加(注册)发动守时器*/
add_timer(&my_timer);//add增加后,定制器开端运转
break;
default:
PRINT_ERR(“writeEINVAL:%c\n”,rev_data);
break;
}
returncount;
}
ssize_tdemodrv_read(structfile*file,char__user*buf,size_tsize,loff_t*ppos)
{
return1;
}
staticintdemodrv_open(structinode*inode,structfile*file)
{
printk(“driver:deviceopen\n”);
return0;
}
intdemodrv_close(structinode*inode,structfile*file)
{
printk(“driver:deviceclose\n”);
return0;
}
staticstructfile_operationsdemo_drv_fops={
.owner=THIS_MODULE,
.open=demodrv_open,
.read=demodrv_read,
.write=demodrv_write,
.release=demodrv_close,
};
intmajor;
staticstructclass*demo_drv_class;
staticstructclass_device*demo_class_dev;
staticint__initdemo_drv_init(void)
{
major=register_chrdev(0,”demo_drv”,&demo_drv_fops);//注册字符驱动获取设备号
demo_drv_class=class_create(THIS_MODULE,”demo_drv_class”);//sys/class下创立类
demo_class_dev=device_create(demo_drv_class,NULL,MKDEV(major,0),NULL,”demo_dev”);/*类下创立设备文件绑定到设备号/dev/demo_dev*/
timer_init_run(demo_class_dev);
return0;
}
staticvoid__exitdemo_drv_exit(void)
{
unregister_chrdev(major,”demodrv”);
device_unregister(demo_class_dev);
class_destroy(demo_drv_class);
/*删去(中止)守时器*/
del_timer(&my_timer);
return0;
}
module_init(demo_drv_init);
module_exit(demo_drv_exit);
如上源码可知,运用一个守时器通常需要如下步骤:
定义一个timer_list结构体的守时器目标。并能够经过TIMER_INITIALIZER快速赋值目标里的成员(中止函数;守时时刻等);
init_timer初始化该定制器(此时守时器还不能走);
能够自定义为守时器目标里的成员赋值(中止函数;守时时刻;私有数据等);
add_timer发动该守时器,守时器开端倒计时;
mod_timer修正当时守时器的数值(复位守时器);
如果要中止(删去)一个守时器,履行del_timer,需要重新发动则继续履行add_timer。

linux

linux定时器的使用示例

咱们常常有设置体系在某一时刻履行相应动作的需求,比如设置电脑什么时分主动锁屏,什么时分主动关机,设置应用程序什么时分主动运转,什么时分主动退出。这些与时刻相关的功用,都需求依靠操作体系中的守时器来完成。
linux中守时器的运用原理很简单,你只需设置一个超时时刻和相应的履行函数,体系就会在超时的时分履行一开始设置的函数。超时的概念有点含糊,它指的是你设定一个时刻,假如当时的时刻超过了你设定的时刻,那就超时了。比如说,你设置五分钟后体系主动关机,体系会记住五分钟后的详细时刻,也便是当时时刻再加上五分钟。过了五分钟后,体系当时时刻已经比方才设置的详细时刻大了,出现超时,于是运转超时行为。
在linux中,运用alarm函数能够设置一个守时器,当守时器超时的时分,会产生SIGALRM信号。因而,要设置超时行为,就得在SIGALRM信号上设置相应的函数。
包含头文件:#include
函数原型:unsignedintalarm(unsignedintseconds);
详细例子如下:
#include
#include
#include
voidSigFun(intsigno){
printf(“SigFunisrunning\n”);
}
intmain(){
if(signal(SIGALRM,SigFun)==SIG_ERR){
perror(“signal\n”);
return-1;
}
alarm(5);
pause();
}
在linux中,一个进程只能有一个守时器,因而当一个进程需求设置多个守时行为时,需求采纳相应的措施,使得一个守时器能够完成多个守时。主要的办法有两种,一种叫时刻链,一种叫时刻堆。
时刻链是将一切守时行为以链表的方法连在一起,同时在进程中保护一个固守时刻超时的守时器。当守时器超时的时分,查看链表上一切的行为是否超时,假如有超时的行为,则运转其行为,并将其从链表中删除。这用办法最大的害处便是需求固守时刻遍历整个链表,造成了比较大的开支。
时刻堆是将一切守时行为以最小堆的方法组织起来,并且在进程中保护一个以堆顶为超时时刻的守时器。当守时器超时时,查看堆顶行为是否超时,假如超时,则运转该行为,并将其从堆顶删除,接着持续查看;假如堆顶行为未超时,则用其超时时刻持续设置守时器。时刻堆不必固守时刻去查看一切守时行为,只需在超时的时分运转相应的超时行为,功率比时刻链高。
在linux中,alarm函数是以秒计时的,当有时咱们需求更小的时刻单位去设置行为,比如毫秒,应该怎么办呢?linux供给setitimer函数,能够供给更精确的守时器。
包含头文件:#include
函数原型:intsetitimer(intwhich,conststructitimerval*new_value,structitimerval*old_value);
参数:
intwhich有三种挑选:
ITIMER_REAL:decrementsinrealtime,anddeliversSIGALRMuponexpiration.
ITIMER_VIRTUAL:decrementsonlywhentheprocessisexecuting,anddeliversSIGVTALRMuponexpiration.
ITIMER_PROF:decrementsbothwhentheprocessexecutesandwhenthesystemisexecutingonbehalfoftheprocess.CoupledwithITIMER_VIRTUAL,thistimerisusuallyusedtoprofilethetimespentbytheapplicationinuserandkernelspace.SIGPROFisdelivered
其中,which为守时器类型,3中类型守时器如下:
ITIMER_REAL:以体系真实的时刻来核算,它送出SIGALRM信号。
ITIMER_VIRTUAL:-以该进程在用户态下花费的时刻来核算,它送出SIGVTALRM信号。
ITIMER_PROF:以该进程在用户态下和内核态下所费的时刻来核算,它送出SIGPROF信号。
第二个参数指定间隔时刻,第三个参数用来回来上一次守时器的间隔时刻,假如不关心该值可设为NULL。
it_interval指定间隔时刻,it_value指定初始守时时刻。假如只指定it_value,便是完成一次守时;假如同时指定it_interval,则超时后,体系会重新初始化it_value为it_interval,完成重复守时;两者都清零,则会铲除守时器。
tv_sec供给秒级精度,tv_usec供给微秒级精度,以值大的为先,注意1s=1000000us。
假如是以setitimer供给的守时器来休眠,只需阻塞等待守时器信号就能够了。
setitimer()调用成功回来0,不然回来-1。

未经允许不得转载:IT技术网站 » linux定时器的使用(示例)
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

志在指尖 用双手敲打未来

登录/注册IT技术大全

热门IT技术

C#基础入门   SQL server数据库   系统SEO学习教程   WordPress小技巧   WordPress插件   脚本与源码下载