alarm函数
函数原型: unsigned int alarm(unsigned int seconds);
函数描述:设置定时器(闹钟)。在指定seconds后,内核会给当前进程发送 14)SIGALRM信号。进程收到该信号,默认动作终止。每个进程都有且唯一的一个定时器。
函数返回值:返回0或者剩余的秒数,无失败。
alarm() returns the number of seconds remaining until any previously
scheduled alarm was due to be delivered, or zero if there was no previ‐
ously scheduled alarm.
alarm(5)-----------sleep(2)---------->alarm(5)->接下来还是5秒后产生SIGALRM信号
return 0; return 3(之前的定时器还差3second结束);
取消定时器:alarm(0),返回旧闹钟剩余的秒数
测试:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
#include <signal.h>
void handler(int signo)
{
printf("signo==[%d]\n",signo);
}
int main()
{
//给内核注册信号捕捉函数,看看是不是发送SIFGALRM信号
signal(SIGALRM,handler);
int n=alarm(10);
printf("n==[%d]\n",n);
sleep(2);
n=alarm(2);//2秒后发送信号
printf("n==[%d]\n",n);
sleep(5);//让进程休息5秒,不然进程结束,也收不到信号了
}
运行结果我们也可以发现给进程发出SIGALRM信号时,该进程直接终止,并没有sleep(5)那么久才结束 (由于 alarm()
函数被 sleep()
函数替代,可能会对定时器造成影响。如果你希望在接收到 SIGALRM
信号后再等待 10 秒钟,可以将 sleep(10)
移到信号处理函数中,并在接收到信号后调用 sleep()
函数。)
闹钟实际执行时间=系统时间+用户时间+损耗时间
我们通过测试电脑一秒中能打印多少的数字(printf("[%d]\n",i++);)可知:
调用printf函数打印数字遇到\n才会打印,打印过程涉及到从用户区到内核区的切换(打印一次切换一次),切换次数越多消耗的时间越长,效率越低,损耗的时间越多。
而我们使用文件重定向操作时(./ arlarm > test.log->写到test.log),由于文件操作带缓冲,所以涉及到用户区到内核区的切换次数大大减少(缓冲区满了才从用户区切换到内核区),从而使损耗大大降低
setitimer函数:
函数原型: int setitimer(int which, const struct itimerval *new_value,
struct itimerval *old_value);
函数作用:设置定时器,可代替alarm函数,精度微秒us,可以实现周期定时。
函数参数:
which:指定定时方式
自然定时:ITIMER_REAL(计算自然时间) This timer counts down in real (i.e., wall clock) time.
At each expiration, a SIGALRM(14) signal is generated.
虚拟空间计时(用户空间):ITIMER_VIRTUAL(只计算进程占用cpu的时间) This timer counts down against the user-mode CPU time
consumed by the process. (The measurement includes CPU
time consumed by all threads in the process.) At each
expiration, a SIGVTALRM signal is generated.
运行时计时(用户+内核)ITIMER_PROF(计算占用cpu及执行系统调用的时间) This timer counts down against the total (i.e., both
user and system) CPU time consumed by the process. (The
measurement includes CPU time consumed by all threads in
the process.) At each expiration, a SIGPROF signal is
generated.
In conjunction with ITIMER_VIRTUAL, this timer can be
used to profile user and system CPU time consumed by the
process.
new value:负责设定timeout时间
old_value:存放旧的timeout值,一般设为NULL
struct itimerval {
struct timeval it_interval;设定以后每几秒执行function(周期)
struct timeval it_value;设定什么时候执行第一次function
};
struct timeval {
time_t tv_sec; 秒
suseconds_t tv_usec; 微秒
};
测试;
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
#include <signal.h>
#include <sys/time.h>
void handler(int signo)
{
printf("signo=[%d]\n",signo);
//alarm(0);可以取消计时器
}
int main()
{
// signal(SIGALRM,handler);
//int setitimer(int which, const struct itimerval *new_value,
// struct itimerval *old_value);
struct itimerval value;
//设置间隔
value.it_interval.tv_sec=1;
value.it_interval.tv_usec=0;//因为在栈上,不初始化会随机值
//设置第一次发信号的时间
value.it_value.tv_sec=2;
value.it_value.tv_usec=0;
setitimer(ITIMER_REAL,&value,NULL);
//一直执行进程
while(1)
{
sleep(1);
}
}
结果:2秒之后每隔1秒打印编号:
如果我们不写SIGALRM的信号处理函数,接收到SIGALRM后会直接终止进程(默认行为)。