数据结构
- 定时器结构:
struct itimerval
{
struct timerval it_value;//Interval for periodic timer,从设置定时器开始到第一次定时器生效的时间
struct timerval it_interval;//Time until next expiration,定时器生效的时间间隔
}
① 若
it_value=0
,系统将无视it_interval
并终止定时器,因此可利用这一特性disable定时器
② 若it_interval=0
,则定时器执行一次后失效
- 时间存储结构:
struct timeval { time_t tv_sec;//秒 suseconds_t tv_usec;//微秒(microseconds) }
定时器类型
-
ITIMER_REAL
:0,自然定时,计算自然时间,实时衰减;当此计时器到期时,将发送SIGALRM信号。 -
ITIMER_VIRTUAL
:1,虚拟空间计时(用户空间),只计算进程占用cpu的时间,进程虚拟时间中的衰减;它只在进程执行时运行;SIGVTALRM信号在到期时发送。 -
ITIMER_PROF
,2,运行时计时(用户+内核),计算占用cpu及执行系统调用的时间,进程虚拟时间和系统代表进程运行时的衰减;它被设计用于解释程序执行的统计分析;每次ITIMER_PROF计时器到期时,都会传递SIGPROF信号。
方法
-
获取系统时间(毫秒级)
注意,获得的数据从1970.01.01开始算起的
int gettimeofday(struct timeval *,void *);
如果第二个参数不为NULL,结果不可预料
-
设置定时器
//参数1:定时器类型 //参数2:指定的定时器 //参数3:调用setitimer之前的旧定时器 int setitimer(int,const struct itimerval *,struct itimerval *); // 成功返回0 //是把你返回-1
-
获取定时器
int getitimer(int,struct itimerval*); //example: getitimer(ITIMER_REAL,&value);
测试代码
#include<iostream>
#include<sys/time.h>
#include<signal.h>
using namespace std;
void testFun(int a)
{
cout<<"Hello,Linux timer~"<<endl;
}
int main()
{
struct timeval curtime;
gettimeofday(&curtime,NULL);
cout<<"curtime.tv_sec:"<<curtime.tv_sec<<endl;
cout<<"curtime.tv_usec:"<<curtime.tv_usec<<endl;
struct itimerval timer;
//周期定时器间隔
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec =1000*500;//0.5s=500ms=500*1000us
//从设置定时器开始到第一次定时器生效的时间
timer.it_value.tv_sec =1;//1秒
timer.it_value.tv_usec =0;
setitimer(ITIMER_REAL, &timer, NULL);
signal(SIGALRM, testFun);
while(1);
return 0;
}
编译:
g++ timer_test.cpp -o timer_test
注意:
tv_usec
的值必须小于1000*1000
,当等于1000*1000
微秒时,应设置tv_sec=1
,否则程序将出现未响应的状态~
sigaction函数
头文件:#include <signal.h>
功能:检查或修改与指定信号相关联的处理动作(可同时两种动作)
//signum:指定要捕获的信号类型
//act:指定新的信号处理方式
//oldact:输出先前信号的处理方式,通常为NULL
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
数据结构:
//sa_handler:函数指针,和signal()的参数handler相同,代表新的信号处理函数,其他意义请参考signal()
//sa_sigaction:是另一个信号处理函数,有三个参数,可获得关于信号的更详细的信息;当 sa_flags 成员的值包含了 SA_SIGINFO 标志时,系统将使用 sa_sigaction 函数作为信号处理函数,否则使用 sa_handler 作为信号处理
//sa_mask:用来指定在信号处理函数执行期间需要被屏蔽的信号,特别是当某个信号被处理时,它自身会被自动放入进程的信号掩码,因此在信号处理函数执行期间这个信号不会再度发生。
//sa_flags:用来设置信号处理的其他相关操作
// SA_RESETHAND:当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL
// SA_RESTART:如果信号中断了进程的某个系统调用,则系统自动启动该系统调用(使被信号打断的系统调用自动重新发起)
// SA_NODEFER :一般情况下, 当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了 SA_NODEFER标记, 那么在该信号处理函数运行时,内核将不会阻塞该信号(使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信号)
// SA_NOCLDSTOP:使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD 信号。
// SA_NOCLDWAIT:使父进程在它的子进程退出时不会收到 SIGCHLD 信号,这时子进程如果退出也不会成为僵尸进程。
// SA_SIGINFO:使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数。
//sa_restorer:此参数未使用,据说已废弃
struct sigaction
{
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
测试代码:
具体看这篇博文→https://www.cnblogs.com/Jacket-K/p/8364874.html
其他结论
- 默认情况下,信号将由主进程接收处理,就算信号处理函数是由子线程注册的
- 对信号的处理是进程中所有的线程共享的
参考文献:
- https://www.beck-ipc.com/api_files/sc145/libc/Elapsed-Time.html
- https://www.cnblogs.com/jordan-tao/archive/2012/11/03/linux_sys_times.html
- https://www.cnblogs.com/wblyuyang/archive/2012/11/13/2768923.html
- https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_time.h.html
- https://www.cnblogs.com/love-DanDan/p/8724237.html
- https://blog.csdn.net/weibo1230123/article/details/81411827
- https://baike.baidu.com/item/sigaction/4515754?fr=aladdin
- https://blog.csdn.net/weibo1230123/article/details/81411827
- https://www.cnblogs.com/Jacket-K/p/8364874.html
- https://blog.csdn.net/u014530704/article/details/81415153