settimer()函数和alarm()函数

来源:互联网 发布:中国工业企业数据 编辑:程序博客网 时间:2024/05/21 09:44

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<unistd.h>
#include<stdio.h>
#include<signal.h>
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<sys/time.h>

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<unistd.h>
      #include<stdio.h>
      #include<sys/time.h>
      #include<signal.h>
      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来定时,不过感觉好像很麻烦

原创粉丝点击