主要内容参考了文章https://blog.csdn.net/sinat_36184075/article/details/80489402
头文件:
#include <time.h>
函数声明:
int timer_settime(timer_t timerid, int flags, const struct itimerspec * new_value, struct itimerspec * old_value);
int timer_gettime(timer_t timerid, struct itimerspec * curr_value);
功能:设置或者获得定时器时间值
参数:
@timerid 定时器标识
@flags 0标识相对时间,1标识绝对时间
@new_value 定时器的新初始值和间隔
@old_value 取值通常为0或NULL,若不为NULL,则返回定时器前一个值
编译:
编译时增加选项 -lrt.
union sigval
{
int sival_int; //integer value
void *sival_ptr; //pointer value
}
struct sigevent
{
int sigev_notify; //notification type
int sigev_signo; //notification signal number
union sigval sigev_value; //Data passed with notification
void (*sigev_notify_function)(union sigval); /* Function used for thread notification (SIGEV_THREAD) */
pthread_attr_t *sigev_notify_attributes; /* Attributes for notification thread (SIGEV_THREAD) */
}
通过将 sigevent中的sigev_notify设定为如下值来定制定时器到期后的行为:
SIGEV_NONE:什么都不做,只提供通过timer_gettime和timer_getoverrun查询超时信息。
SIGEV_SIGNAL: 当定时器到时,内核会将sigev_signo所指定的信号传送给进程。在信号处理程序中,si_value会被设定会sigev_value。
SIGEV_THREAD: 当定时器到时,内核会(在此进程内)以sigev_notification_attributes为线程属性创建一个线程,并且让它执行sigev_notify_function,传入sigev_value作为为一个参数。
struct timespec {
time_t tv_sec; /* Seconds */
long tv_nsec; /* Nanoseconds */
};
struct itimerspec {
struct timespec it_interval; /* Timer interval */
struct timespec it_value; /* Initial expiration */
};
函数声明:
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
参数:
signum--指定的信号,这里使用SIGUSR1
act结构体--设置信号编号为signum的处理方式
oldact结构体--保存上次的处理方式
结构体:
struct sigaction
{
void (*sa_handler)(int); //信号响应函数地址
void (*sa_sigaction)(int, siginfo_t *, void *); //当sa_flags为SA——SIGINFO时才使用
sigset_t sa_mask; //说明一个信号集在调用捕捉函数之前,会加入进程的屏蔽中,当捕捉函数返回时,还原
int sa_flags; //设置成0时,sa_handler指向一个参数的函数
void (*sa_restorer)(void); //未用
};
举例1:采用新线程派驻的通知方式
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
static int count = 10; //执行10次后结束
void timer_thread(union sigval v)
{
count--;
printf("%s param: %d, count: %d\n", __FUNCTION__, v.sival_int, count);
}
int main()
{
timer_t timerid;
struct sigevent evp;
memset(&evp, 0, sizeof(struct sigevent)); //清零
evp.sigev_value.sival_int = 12; //标识定时器,回调函数可以获得
evp.sigev_notify = SIGEV_THREAD; //线程通知的方式,创建新线程
evp.sigev_notify_function = timer_thread; //线程函数名,当定时器到时后调用该函数
if (timer_create(CLOCK_REALTIME, &evp, &timerid) == -1)
{
perror("fail to timer_create");
exit(-1);
}
// 启动后等待it.it_value时间后第一次调用,然后每次间隔it.it_interval时调用
struct itimerspec it;
it.it_interval.tv_sec = 2; // timer函数执行频率为2s运行1次
it.it_interval.tv_nsec = 0;
it.it_value.tv_sec = 4; // 倒计时4秒开始调用timer函数
it.it_value.tv_nsec = 0;
if (timer_settime(timerid, 0, &it, NULL) == -1)
{
perror("fail to timer_settime");
exit(-1);
}
while (count);
return 0;
}
举例2:通知方式为信号的处理方式
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#define CLOCKID CLOCK_REALTIME
void sig_handler(int signo)
{
printf("timer_signal function! %d\n", signo);
}
int main()
{
timer_t timerid;
struct sigevent evp;
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = sig_handler;
act.sa_flags = 0;
// XXX int sigaddset(sigset_t *set, int signum); //将signum指定的信号加入set信号集
// XXX int sigemptyset(sigset_t *set); //初始化信号集
sigemptyset(&act.sa_mask);
//SIGUSR1 用户自定义信号 默认处理:进程终止
//SIGUSR2 用户自定义信号 默认处理:进程终止
if (sigaction(SIGUSR1, &act, NULL) == -1)
{
perror("fail to sigaction");
exit(-1);
}
memset(&evp, 0, sizeof(struct sigevent));
evp.sigev_signo = SIGUSR1;
evp.sigev_notify = SIGEV_SIGNAL;
if (timer_create(CLOCK_REALTIME, &evp, &timerid) == -1)
{
perror("fail to timer_create");
exit(-1);
}
struct itimerspec it;
it.it_interval.tv_sec = 2;
it.it_interval.tv_nsec = 0;
it.it_value.tv_sec = 1;
it.it_value.tv_nsec = 0;
if (timer_settime(timerid, 0, &it, 0) == -1)
{
perror("fail to timer_settime");
exit(-1);
}
struct itimerspec newit;
if (timer_gettime(timerid, &newit) == 0)
{
printf("interval.tv_sec: %ld \n interval.tv_nsec: %ld \n value.tv_sec: %ld \n value.tv_nsec: %ld \n",
newit.it_interval.tv_sec, newit.it_interval.tv_nsec, newit.it_value.tv_sec, newit.it_value.tv_nsec);
}
while(1);
return 0;
}