未加星标

Linux使用一个定时器实现设置任意数量定时器功能

字体大小 | |
[系统(linux) 所属分类 系统(linux) | 发布者 店小二03 | 时间 | 作者 红领巾 ] 0人收藏点击收藏

为什么需要这个功能,因为大多数计算机软件时钟系统通常只能有一个时钟触发一次中断。当运行多个任务时,我们会想要多个定时器 的时钟跟踪并发这样可以生成正确的时间重叠,操作系统这样做。

本例子是为了实现使用linux下的一个定时器,实现任一数量的定时器功能。

首先我们需要一些数据类型用来描述时钟数据结构

#include <stdio.h>
#include<time.h>
#define TRUE 1
#define FALSE 0
#define MAX_TIMERS ... 最大时钟数量
typedef timerval TIME; 定义时间类型
#define VERY_LONG_TIME ... 最大时间长度
struct timer {
int inuse; 时钟是否可用
TIME time; 定时时间长度
char *event; 是否超时
} timers[MAX_TIMERS]; /* set of timers */

每个定时器都以这个数据结构来描述,第一个成员用来描述时钟是否正在使用,第二个成员是这个定时器的定时时间,第三个成员是是一个指针,*event初始化应该为0,当他被置为1,我们知道这个定时器已经超时了,和他相关的任务可以执行。

接下来是定时器数组的初始化,这里将每个时钟inuse成员设置为FALSE,表示时钟不可用。

void
timers_init() {
struct timer *t;
for (t=timers;t<&timers[MAX_TIMERS];t++)
t->inuse = FALSE;
}

现在开始是结构实现部分

首先写到的timer_undeclare这个函数,这个函数与后面的timer_declare相对立。主要作用是清除一个定时器。

有很多方法可以用来保存定时器的定时记录。没有复杂时钟硬件的机器通常在每一个时钟周期处理一个中断处理程序。然后软件就在处理程序中获取系统时间,然后判断是否设置的定时器超时。

很多比较聪明的机器可以在硬件中设置定时时间,一旦时间超时,就触发一个硬件中断。这同样适用与软件中断。

他们通过一个 定义一个time_now来记录当前的系统时间,volatile告诉机器每次从寄存器取值,防止数据被系统优化。

volatile TIME time_now

接下来定义一系列数据来记录 timer_next 指接下来要我们想要计时的定时器。time_timer_set保存最后一次获取的系统时间。

struct timer *timer_next = NULL;/* timer we expect to run down next */
TIME time_timer_set; /* time when physical timer was set */
//取消一个定时器
void timer_undeclare(struct timer *t)
{
  disable_interrupts();
  if(!t->inuse)
  {
    enable_interrupts();
    return ;
  }
  t->inuse=0;
  if(t==timer_next)
  {
    if(time(&time_now)<0)
    perror("time error");
    timers_update(time_now-time_timer_set);
    if(timer_next)
    {
      start_physical_timer(&timer_next->time);
      time_timer_set=time_now;
    }
  }
  enable_interrupts();
}

timer_undeclare作用为取消一个定时器。首先让中断失效,这很重要,因为时钟数据结构数据是在各进程中共享的,是可以在其他中断中被修改的,为了防止不必要的错我,这个取消操作应该为一个原子操作。开始我们先检测是否这个时钟已经无效了。如果有效,则设置inuse使其失效。如果我们要取消的定时器正好是下一个期望等待的定时器。那我们要重新指定下一个期望等待的定时器。在此之前所有定时器都要更新一下前一个定时器已经走过的时间。

接下来我们看到timers_update(time_t ti)函数

//更新定时器表时间
void timers_update(time_t time)
{
  static struct timer timer_last={
  0,
  {},
  NULL
  };
  timer_last.time.tv_sec=10;
  struct timer *t;
  timer_next=&timer_last;
  for(t=timers;t<&timers[MAX_TIMERS];t++)
  {
    if(t->inuse)
    {
      if(time<t->time.tv_sec){
      t->time.tv_sec-=time;
      if(t->time.tv_sec<\
      timer_next->time.tv_sec)
        timer_next=t;
      }else
      {
        *(t->event)=1;
        t->inuse=0;
      }
    }
  }
  if(!timer_next->inuse)timer_next=0;
}

此函数作用是更新所有有效定时器的时间长,同时将timer_next指向当前延时时间最短的一个定时器。如没有定时器,则将timer_next设置为空。

timer_declare 加入一个定时器

struct timer * timer_declare(TIME *ti,char *event)
{
  struct timer *t;
  disable_interrupts();
  for(t=timers;t<&timers[MAX_TIMERS];t++)
  {
    if(!t->inuse)break;
  }
  if(t==&timers[MAX_TIMERS])
  {
    enable_interrupts();
    return 0;
  }
  t->event=event;
  t->time.tv_sec=ti->tv_sec;
  t->time.tv_usec=ti->tv_usec;
  if(!timer_next)
  {
    if(time(&time_now)<0)
    perror("time() error");
    time_timer_set=time_now;
    start_physical_timer(&((timer_next=t)->time));
  }else if((ti->tv_sec+time_now)<(\
  timer_next->time.tv_sec+time_timer_set))
  {
    if(time(&time_now)<0)
    perror("time error");
    timers_update(time_now-time_timer_set);
    time_timer_set=time_now;
    start_physical_timer(&((timer_next=t)->time));
  }else
  {
  }
  t->inuse=1;
  enable_interrupts();
  return t;
}

首先找到一个可用的定时器表项,设置相关参数。

接下来判断如果timer_next为空,那么说明定时器表项没有定时器需要定时,那我们直接将timer_next指向新加入定时器,开始计时。

如果新加入定时器需要延时时间比当前正在延时的定时器的剩余时间还要短,则更新定时器表,并计时当前加入的定时器。

在处理完当前定时器事件后,将新加入的定时器的inuse置1.

接下来是定时器中断处理函数

//定时器中断处理函数
void timer_interrupt_hander(int signo)
{
  printf("interrupt_hander\n");
  if(time(&time_now)<0)
    perror("time() error");
  timers_update(time_now-time_timer_set);
  if(timer_next)
  {
    time_timer_set=time_now;
    start_physical_timer(&timer_next->time);
  }
}

这里我们打印一串字符来证明定时器时间的触发,首先要做的先更新定时器表,然后将time_timer_set设置成当前系统时间,继续进行下一个定时器事件,直到所有定时器都处理完毕。

接下来几个是LINUX系统相关函数

//失效定时器中断
void disable_interrupts()
{sigset_t new_mask;
sigemptyset(&new_mask);
sigaddset(&new_mask,SIGALRM);
if(sigprocmask(SIG_BLOCK,&new_mask,NULL)<0)
perror("SIG_BLOCK error");
}
//使能定时器中断
void enable_interrupts()
{
sigset_t new_mask;
sigemptyset(&new_mask);
sigaddset(&new_mask,SIGALRM);
if(sigprocmask(SIG_UNBLOCK,&new_mask,NULL)<0)
perror("SIG_UNBLOCK error");
}
//开启一个定时器工作
void start_physical_timer(TIME* time)
{
if(signal(SIGALRM,timer_interrupt_hander)==SIG_ERR)
perror("signal error");
struct itimerval new_value;
sigset_t zero_mask;
sigemptyset(&zero_mask);
new_value.it_value.tv_sec=time->tv_sec;
new_value.it_value.tv_usec=time->tv_usec;
new_value.it_interval.tv_sec=0;
new_value.it_interval.tv_usec=0;
setitimer(ITIMER_REAL,&new_value,NULL);
sigsuspend(&zero_mask);
}

主函数测试部分

#include<stdio.h>
#include<signal.h>
#include"multtime.h"
#include<stdlib.h>
#include<unistd.h>
int main()
{
pid_t pid;
TIME time1,time2,time3;
time1.tv_sec=6;
time1.tv_usec=0;
time2.tv_sec=4;
time2.tv_usec=0;
time3.tv_sec=2;
time3.tv_usec=0;
timer_init();
if((pid=fork())<0)
{
perror("fork() error");
}
else if(pid==0)
{
printf("child 1\n");
timer_undeclare(timer_declare(&time1,0));
}
else
{
if((pid=fork())<0)
{
perror("fork error");
}
else if(pid==0)
{
printf("child 2\n");
timer_undeclare(timer_declare(&time3,0));
}
else
{
printf("parent\n");
timer_undeclare(timer_declare(&time2,0));
}
}
exit(0);
}

实验结果:

parent
child 2
child 1
interrupt_hander
interrupt_hander
interrupt_hander
总结

以上所述是小编给大家介绍的Linux使用一个定时器实现设置任意数量定时器功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

本文系统(linux)相关术语:linux系统 鸟哥的linux私房菜 linux命令大全 linux操作系统

主题: Linux数据结构TI数据谢大RY
分页:12
转载请注明
本文标题:Linux使用一个定时器实现设置任意数量定时器功能
本站链接:http://www.codesec.net/view/563540.html
分享请点击:


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 系统(linux) | 评论(0) | 阅读(52)