Linux应用层定时器

alarm

alarm会设置一个定时器,当时间到期后会触发SIGALRM信号,该信号可能会打断系统调用的执行,它使用的定时器和setitimer对应的ITIMER_REAL是同一个。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "include/debug.h"

void sig_func(int signo)
{
	pr_info("SIGALRM received!\n");
}

 int set_signal(int signo, void func(int signo))
 {
     struct sigaction act, oact;
 
     act.sa_handler = func;
     sigemptyset(&act.sa_mask);
     act.sa_flags = 0;
 #ifdef SA_INTERRUPT
     act.sa_flags |= SA_INTERRUPT;
 #endif

     if (sigaction(signo, &act, &oact) < 0) {
         printf("sigaction error,%s\n",strerror(errno));
         return 1;
     }
     return 0;
 }

int main()
{
	char buf[10];
	int fd;

	set_signal(SIGALRM, sig_func);
	alarm(5);
	pr_info("block read\n");
	read(STDIN_FILENO, buf, 10);
	pr_info("read returns\n");

	return 0;
}

运行结果:

$ ./timer_test 
[6858] INFO:  block read
[6858] INFO:  SIGALRM received!
[6858] INFO:  read returns

alarm会打断阻塞的系统调用,因此使用时要注意处理errno。

setitimer

#include 

int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, const struct itimerval *new_value,
              struct itimerval *old_value);

setitimer根据参数的不同可能会产生三种不同的信号:

 ITIMER_REAL    到期产生SIGALRM信号
 ITIMER_VIRTUAL 到期产生SIGVTALRM信号
 ITIMER_PROF    到期产生SIGPROF信号

既然会产生信号,同样不可避免的会打断阻塞的系统调用。

alarm和setitimer的关系

当setitimer设置参数ITIMER_REAL时产生的是SIGALRM信号,并且使用的定时器也属于同一个,因此如果和alarm共用可能会产生意象不到的结果,因此要慎重。

posix timer API

setitimer限定每个进程只能设置一个定时器,对于多个定时任务,只能自己实现一个timer链表去处理,对于需要多个定时任务的进程不太友好。
posix timer API允许一个进程可以创建很多个定时器任务,这是它的一大优势:

timer_create: 创建了一个定时器。
timer_settime: 启动或者停止一个定时器。
timer_gettime: 返回到下一次到期的剩余时间值。
timer_getoverrun: 返回上次定时器到期时超限值。
timer_delete: 停止并删除一个定时器。

timer的触发方式也比较灵活,可以选择上报signal,也可以选择运行一个thread function,具体参见man手册。clockid为:

CLOCK_REALTIME
CLOCK_MONOTONIC
CLOCK_PROCESS_CPUTIME_ID
CLOCK_THREAD_CPUTIME_ID 

alarm timer

上面介绍的timer都是跟随系统tick进行计算时间的,当系统处于休眠状态时,这些tick都会停掉,因此定时器也会失效,此时如果想要定时器继续工作,就必须使用alarm timer。
Linux系统中有两个时钟可以在系统休眠时继续运行,realtime alarm和boottime alarm。alarm timer借助RTC设备,一直供电且具备唤醒功能,在系统进入suspend过程中,将最近一次超时时间写入RTC设备,超时后会唤醒系统执行timer超时函数。
想要使用这两个alarm timer,依然可以使用posix timer API。
对应的clockid为:

CLOCK_REALTIME_ALARM
CLOCK_BOOTTIME_ALARM

你可能感兴趣的:(Linux,C快速指南)