分类: LINUX
2012-05-29 13:24:37
unsigned int alarm(unsigned int seconds)函数,用来定时,当到达定时的时间后,内核会发送SIGALRM信号给进程,如果进程忽略该信号,该进程会终止,也可以自己定义 SIGALRM信号的处理函数,当然是用的是signal()函数
void (*signal)(int signo, void (*func)(int)))(int );
signo 指定要处理的信号,信号处理函数void func(),当要处理多个信号时候,func(int sig)用sig参数传进信号,在func中判断信号类型,然后指定处理
alarm()函数并不轮询定时,因此可以在func()中收到SIGALRM后,在次设定alarm()函数
但是下面介绍的settimer()函数产生的定时信号讲会持续有效,
example:
#include
#include
#include
void fun(int sig);
int main()
{
alarm(3);
signal(SIGALRM,fun);
// pause(); //wait the signal
while(1); //always wait for signal
return 0;
}
void fun(int sig)
{
if(sig==SIGALRM)
printf("get timer alarm!/n");
else
printf("get timer failed!/n");
alarm(3);
}
仍旧有一个函数,settimer() 也是用来定时的,定时到了后内核会发出信号,
函数原型
#include
int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
{
struct task_struct *tsk = current;
struct hrtimer *timer;
ktime_t expires;
cputime_t cval, cinterval, nval, ninterval;
/*
* Validate the timevals in value.
*
* Note: Although the spec requires that invalid values shall
* return -EINVAL, we just fixup the value and print a limited
* number of warnings in order not to break users of this
* historical misfeature.
*
* Scheduled for replacement in March 2007
*/
check_itimerval(value);
switch (which) {
case ITIMER_REAL:
again:
spin_lock_irq(&tsk->sighand->siglock);
timer = &tsk->signal->real_timer;
if (ovalue) {
ovalue->it_value = itimer_get_remtime(timer);
ovalue->it_interval= ktime_to_timeval(tsk->signal->it_real_incr);
}
/* We are sharing ->siglock with it_real_fn() */
if (hrtimer_try_to_cancel(timer) < 0) {
spin_unlock_irq(&tsk->sighand->siglock);
hrtimer_wait_for_timer(&tsk->signal->real_timer);
goto again;
}
expires = timeval_to_ktime(value->it_value);
if (expires.tv64 != 0) {
tsk->signal->it_real_incr =
timeval_to_ktime(value->it_interval);
hrtimer_start(timer, expires, HRTIMER_MODE_REL);
}
else
tsk->signal->it_real_incr.tv64 = 0;
spin_unlock_irq(&tsk->sighand->siglock);
break;
case ITIMER_VIRTUAL:
nval = timeval_to_cputime(&value->it_value);
ninterval = timeval_to_cputime(&value->it_interval);
read_lock(&tasklist_lock);
spin_lock_irq(&tsk->sighand->siglock);
cval = tsk->signal->it_virt_expires;
cinterval = tsk->signal->it_virt_incr;
if (!cputime_eq(cval, cputime_zero) || !cputime_eq(nval, cputime_zero)) {
if (cputime_gt(nval, cputime_zero))
nval = cputime_add(nval,
jiffies_to_cputime(1));
set_process_cpu_timer(tsk, CPUCLOCK_VIRT,&nval, &cval);
}
tsk->signal->it_virt_expires = nval;
tsk->signal->it_virt_incr = ninterval;
spin_unlock_irq(&tsk->sighand->siglock);
read_unlock(&tasklist_lock);
if (ovalue) {
cputime_to_timeval(cval, &ovalue->it_value);
cputime_to_timeval(cinterval, &ovalue->it_interval);
}
break;
case ITIMER_PROF:
nval = timeval_to_cputime(&value->it_value);
ninterval = timeval_to_cputime(&value->it_interval);
read_lock(&tasklist_lock);
spin_lock_irq(&tsk->sighand->siglock);
cval = tsk->signal->it_prof_expires;
cinterval = tsk->signal->it_prof_incr;
if (!cputime_eq(cval, cputime_zero) ||!cputime_eq(nval, cputime_zero)) {
if (cputime_gt(nval, cputime_zero))
nval = cputime_add(nval,jiffies_to_cputime(1));
set_process_cpu_timer(tsk, CPUCLOCK_PROF,&nval, &cval);
}
tsk->signal->it_prof_expires = nval;
tsk->signal->it_prof_incr = ninterval;
spin_unlock_irq(&tsk->sighand->siglock);
read_unlock(&tasklist_lock);
if (ovalue) {
cputime_to_timeval(cval, &ovalue->it_value);
cputime_to_timeval(cinterval, &ovalue->it_interval);
}
break;
default:
return -EINVAL;
}
return 0;
}
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue));
setitimer()比alarm功能强大,支持3种类型的定时器:
ITIMER_REAL : 以系统真实的时间来计算,它送出SIGALRM信号。
ITIMER_VIRTUAL : -以该进程在用户态下花费的时间来计算,它送出SIGVTALRM信号。
ITIMER_PROF : 以该进程在用户态下和内核态下所费的时间来计算,它送出SIGPROF信号。
setitimer()第一个参数which指定定时器类型(上面三种之一);第二个参数是结构itimerval的一个实例;第三个参数可不做处理。
setitimer()调用成功返回0,否则返回-1。
struct itimercal:
struct itimerval {
struct timeval it_interval; /* timer interval */
struct timeval it_value; /* current value *
};
itimerval结构中的it_value是减少的时间,当这个值为0的时候就发出相应的信号了. 然后再将it_value设置为it_interval值.这样就实现了轮询的定时,而不是想alarm那样只能定时一次,而且其精确度也很高
看例子:
#include
#include
#include
#include
void fun(int sig);
int main()
{
struct itimerval val;
val.it_value.tv_sec=3;
val.it_value.tv_usec=0;
val.it_interval.tv_sec=3;
val.it_interval.tv_usec=0;
setitimer(ITIMER_REAL,&val,NULL);
signal(SIGALRM,fun);
while(1); //always wait for signal
return 0;
}
void fun(int sig)
{
if(sig==SIGALRM)
printf("get timer alarm!/n");
else
printf("get timer failed!/n");
}
setitimer()为其所在进程设置一个定时器,如果itimerval.it_interval不为0(it_interval的两个域都不为0),则该定时器将持续有效(每隔一段时间就会发送一个信号)
注意:Linux信号机制基本上是从Unix系统中继承过来的。早期 Unix系统中的信号机制比较简单和原始,后来在实践中暴露出一些问题,因此,把那些建立在早期机制上的信号叫做"不可靠信号",信号值小于 SIGRTMIN(SIGRTMIN=32,SIGRTMAX=63)的信号都是不可靠信号。这就是"不可靠信号"的来源。它的主要问题是:进程每次处理 信号后,就将对信号的响应设置为默认动作。在某些情况下,将导致对信号的错误处理;因此,用户如果不希望这样的操作,那么就要在信号处理函数结尾再一次调 用signal(),重新安装该信号。
Linux实现定时还有一种方法,就是是用RTC来定时,不过感觉好像很麻烦