适用于精度要求不高的场景,比如几秒。
函数原型:
unsigned int alarm(unsigned int seconds);
函数说明:
该种定时器方法是通过alarm()函数和signal()函数配合完成,alarm函数用来定时,当到达定时的时间后,内核会发送SIGALARM信号给进程,默认会结束进程。也可以通过signal函数为信号SIGALRM设置处理函数,若参数seconds 为0,则之前设置的闹钟会被取消,并将剩下的时间返回;
函数返回值:如果进程设置了闹钟时间,在调用alarm()之后,则返回上一个闹钟时间,否则返回0,出错返回-1。
alarm()执行后,进程将继续执行,在后期(alarm以后)的执行过程中将会在seconds秒后收到信号SIGALRM并执行其处理函数。
示例1:
#include
#include
#include
#include
#include //alarm的库
int count;
void sigalrm_func(int sig){
count++;
printf("alarm![%d]\n",count);
alarm(1);
printf("over\n");
return;
}
int main(int argc,char *argv[])
{
signal(SIGALRM, sigalrm_func);
alarm(2);
printf("see\n");
while(1)
{
if(count == 3)
break;
}
}
程序先是等待定时2秒然后发送信号触发调用函数,然后在调用函数每一秒再设置一次alarm触发调用函数,结果如下:
示例2:
#include
#include
#include
#include
int main(int argc, char *argv[])
{
sigset_t block;
sigemptyset(&block);
sigaddset(&block, SIGALRM);
sigprocmask(SIG_BLOCK, &block, NULL);
while (1) {
printf("%ld\n", time(NULL));
alarm(3);
printf("see\n");
sigwaitinfo(&block, NULL);
}
return 0;
}
输出结果:
其中几个函数解释:
sigwaitinfo()函数:
#include
int sigwaitinfo(sigset_t *set, siginfo_t *info)
阻塞一个进程直到特定信号发生,但信号到来时不执行信号处理函数,而是返回信号值。 调用该函数的典型代码为:
sigwaitinfo();
sigset_t newmask;
int rcvd_sig;
siginfo_t info;
sigemptyset(&newmask);
sigaddset(&newmask, SIGRTMIN);
sigprocmask(SIG_BLOCK, &newmask, NULL);
rcvd_sig = sigwaitinfo(&newmask, &info);
if(rcvd_sig == -1)
{
//…...
}
其中:
1. siget_t 信号集定义为一种数据类型,用来描述信号的集合:
typedef struct{
unsigned long sig[_NSIG_WORDS];
}sigset_t
2.int sigemptyset(sigset_t* set)
函数说明:用来将参数set信号集初始化并清空。
返回值:成功返回0,错误返回-1。
3.int sigaddset(sigset_t* set, int signum)
函数说明:用来将signum代表的信号加入至参数set信号集里。
返回值:成功返回0,错误返回-1。
4.int sigpromask(int how, const sigset_t* set, sigset_t* oldset)
函数说明:用来改变目前的信号遮罩,其操作依参数how来决定。
返回值:成功返回0,错误返回-1。
5.void (signal(int signum, void( handler)(int)))(int);
函数说明: signal()会依据参数signum指定的信号编号来设置该信号的处理函数,当指定的信号到达时就会跳转参数handler指定的函数执行。
返回值:返回先前的信号处理函数指针,如果有错误返回SIG_ERR(-1)
示例3:
不同情况的alarm的返回值
#include
#include
#include
unsigned a;
void fun(int sig)
{
if(sig== SIGALRM)
printf("gettimer alarm!\n");
else
printf("gettimer failed!\n");
}
int main(int argc,char *argv[])
{
unsigned int a,b;
alarm(6);
sleep(2);
a = alarm(3);
printf("The rest time of the first alarm is %u s\n",a);
b = alarm(2);
signal(SIGALRM,fun);
int i = 0;
for(i=0;i<3;i++)
{
printf("%d\n",i);
sleep(1);
}
printf("The return valuable of the last alarm is %u s\nend\n",b);
return 0;
}
输出结果:
setitimer()为Linux的API,不同于C语言的StandardLibrary。setitimer()有两个功能,
一是指定一段时间后,才执行某个function,类似alarm,但是精度更高;
二是每间隔一段时间就调用某个函数;
函数原型:
int setitimer(int which, const struct itimerval *new_value,
struct itimerval *old_value);
需要包含头文件 #include
其中:
which: 指定定时器类型 ,setitimer 支持三种类型定时器:
ITIMER_REAL: 以系统真实的时间来计算,发送SIGALRM信号。
ITIMER_VIRTUAL: -以该进程在用户态下花费的时间来计算,发送SIGVTALRM信号。
ITIMER_PROF: 以该进程在用户态下和内核态下所费的时间来计算,发送SIGPROF信号。
new_value, old_value 皆为itimerval 结构的实例:
struct itimerval
{
struct timerval it_interval; //指定间隔时间
struct timerval it_value; //指定初始定时时间
}
struct timeval {
time_t tv_sec; // 秒
suseconds_t tv_usec; // 微妙
};
itimeval由两个timeval结构体组成,timeval包含tv_sec和tv_usec两部分,其中tv_sec为秒,tv_usec为微秒(即1/1000000秒)
其中的new_value参数用来对计时器进行设置,it_interval为计时间隔,it_value为延时时长,下面例子中表示的是在setitimer方法调用成功后,延时1微秒便触发一次SIGALRM信号,以后每隔200毫秒触发一次SIGALRM信号。settimer工作机制是,先对it_value倒计时,当it_value为零时触发信号,然后重置为it_interval,继续对it_value倒计时,一直这样循环下去。
基于此机制,setitimer既可以用来延时执行,也可定时执行。
假如it_value为0是不会触发信号的,所以要能触发信号,it_value得大于0;如果it_interval为零,只会延时,不会定时(也就是说只会触发一次信号)。
old_value参数,通常用不上,设置为NULL,它是用来存储上一次setitimer调用时设置的new_value值。
示例1 :
#include
#include
#include
#include
#include
int count = 0;
void set_timer()
{
struct itimerval itv;
memset(&itv,0,sizeof(itv));
itv.it_interval.tv_sec = 1;//每隔1秒
itv.it_interval.tv_usec = 0;
itv.it_value.tv_sec = 3;//第一次3秒
itv.it_value.tv_usec = 0;
int ret = setitimer(ITIMER_REAL, &itv, NULL);
if(ret)
{
printf("setitimer failed!/n");
}
}
void sigalrm_handler(int sig)
{
if(sig == SIGALRM)
{
count++;
printf("caught signal.. %d\n", count);
}
else
{
printf("caught signal failed!\n");
}
}
int main()
{
signal(SIGALRM, sigalrm_handler);
set_timer();
while (count < 5)
{}
exit(0);
}
输出结果:
示例2: 阻塞的例子
#include
#include
#include
#include
int main(int argc, char *argv[])
{
sigset_t block;
struct itimerval itv;
sigemptyset(&block);
sigaddset(&block, SIGALRM);
sigprocmask(SIG_BLOCK, &block, NULL);
itv.it_interval.tv_sec = 2;
itv.it_interval.tv_usec = 0;
itv.it_value = itv.it_interval;
setitimer(ITIMER_REAL, &itv, NULL);
while (1)
{
printf("%ld\n", time(NULL));
printf("see\n");
sigwaitinfo(&block, NULL);
}
return 0;
}
输出结果:
关于POSIX 定时器 详细总结请看下一篇
linux 下 alarm(), setitimer 定时器与 POSIX 定时器 timer_settime()对比总结 (下)
定时器函数SetTime与setitimer
linux c stitimer 用法说明
Linux下的定时器以及POSIX定时器:timer_settime()