介绍:Linux系统提供了timerfd系列的定时函数,其具体函数名如下
#include <sys/timerfd.h>
int timerfd_create(int clockid, int flags);
int timerfd_settime(int fd, int flags,
const struct itimerspec *new_value,
struct itimerspec *old_value);
int timerfd_gettime(int fd, struct itimerspec *curr_value);
timerfd函数可以通过文件描述符来通知定时事件,这就使得定时器也符合Linux下一切皆文件的哲学思想,并且可以很方便的使用select, poll和epoll去监测定时器事件。
下面就介绍这三个系统函数的基本用法。
1、不多比比,直接贴代码
(实现一个10ms的高精度定时器!!!)
#include <sys/timerfd.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/epoll.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
void print_elapsed_time(void);
static void msec2tspec(int msec, struct timespec *ts)
{
if (msec) {
ts->tv_sec = msec / 1000;
ts->tv_nsec = (msec % 1000) * 1000000;
} else {
ts->tv_sec = 0;
ts->tv_nsec = 0;
}
}
int main(void)
{
int timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
if (timerfd == -1)
{
handle_error("timerfd_create");
}
struct itimerspec new_value = {};
msec2tspec(10, &new_value.it_value);
msec2tspec(10, &new_value.it_interval);
if (timerfd_settime(timerfd, 0, &new_value, NULL) == -1)
{
handle_error("timerfd_settime");
}
print_elapsed_time();
printf("timer started\n");
int epollfd = epoll_create(1); // or epoll_create(1)
if (epollfd == -1)
{
handle_error("epoll_create1");
}
struct epoll_event ev;
ev.events = EPOLLIN; // 表示该文件描述符可以读的时候就触发
ev.data.fd = timerfd;
epoll_ctl(epollfd, EPOLL_CTL_ADD, timerfd, &ev);
const int maxEvents = 5; // 也可以设置为1
struct epoll_event events[maxEvents];
while (1)
{
int nfd = epoll_wait(epollfd, events, maxEvents, -1);
if (nfd > 0)
{
for (int i = 0; i < nfd; ++i)
{
if (events[i].data.fd == timerfd)
{
uint64_t exp = 0;
int ret = read(timerfd, &exp, sizeof(uint64_t));
if (ret != sizeof(uint64_t))
{
handle_error("read timerfd");
}
print_elapsed_time();
}
}
}
}
return 0;
}
void print_elapsed_time(void)
{
static struct timeval start = {};
static int first_call = 1;
if (first_call == 1)
{
first_call = 0;
if (gettimeofday(&start, NULL) == -1)
{
handle_error("gettimeofday");
}
}
struct timeval current = {};
if (gettimeofday(¤t, NULL) == -1)
{
handle_error("gettimeofday");
}
static int old_secs = 0, old_usecs = 0;
int secs = current.tv_sec - start.tv_sec;
int usecs = current.tv_usec - start.tv_usec;
if (usecs < 0)
{
--secs;
usecs += 1000000;
}
usecs = (usecs + 500)/1000; // 四舍五入
if (secs != old_secs || usecs != old_usecs)
{
printf("%d.%03d\n", secs, usecs);
old_secs = secs;
old_usecs = usecs;
}
}
结果如下:
0.850
0.860
0.870
0.880
0.890
0.900
0.910
0.920
0.930
0.940
0.950
0.960
0.970
0.980
0.990
1.000
1.011
分割线~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
为了方便大家移植,直接编译成头文件跟源文件的形式了
#include "timer_sdk.h"
void print_elapsed_time(void)
{
static struct timeval start = {};
static int first_call = 1;
if (first_call == 1)
{
first_call = 0;
if (gettimeofday(&start, NULL) == -1)
{
handle_error("gettimeofday");
}
}
struct timeval current = {};
if (gettimeofday(¤t, NULL) == -1)
{
handle_error("gettimeofday");
}
static int old_secs = 0, old_usecs = 0;
int secs = current.tv_sec - start.tv_sec;
int usecs = current.tv_usec - start.tv_usec;
if (usecs < 0)
{
--secs;
usecs += 1000000;
}
usecs = (usecs + 500)/1000; // 四舍五入
if (secs != old_secs || usecs != old_usecs)
{
printf("%d.%03d\n", secs, usecs);
old_secs = secs;
old_usecs = usecs;
}
}
static void msec2tspec(int msec, struct timespec *ts)
{
if (msec) {
ts->tv_sec = msec / 1000;
ts->tv_nsec = (msec % 1000) * 1000000;
} else {
ts->tv_sec = 0;
ts->tv_nsec = 0;
}
}
int create_tick_timer(int32_t timeout,int32_t period,int (*p)(int value),int& timerfd,int&epollfd)
{
int (*func_tick) (int value);
func_tick=p;
timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
if (timerfd == -1)
{
handle_error("timerfd_create");
}
struct itimerspec new_value = {};
msec2tspec(timeout, &new_value.it_value);
msec2tspec(period, &new_value.it_interval);
if (timerfd_settime(timerfd, 0, &new_value, NULL) == -1)
{
handle_error("timerfd_settime");
}
printf("timer started\n");
epollfd = epoll_create(1); // or epoll_create(1)
if (epollfd == -1)
{
handle_error("epoll_create1");
}
struct epoll_event ev;
ev.events = EPOLLIN; // 表示该文件描述符可以读的时候就触发
ev.data.fd = timerfd;
epoll_ctl(epollfd, EPOLL_CTL_ADD, timerfd, &ev);
const int maxEvents = 5; // 也可以设置为1
struct epoll_event events[maxEvents];
while (1)
{
int nfd = epoll_wait(epollfd, events, maxEvents, -1);
if (nfd > 0)
{
for (int i = 0; i < nfd; ++i)
{
if (events[i].data.fd == timerfd)
{
uint64_t exp = 0;
int ret = read(timerfd, &exp, sizeof(uint64_t));
if (ret != sizeof(uint64_t))
{
handle_error("read timerfd");
}
func_tick(i);
}
}
}
}
return 0;
}
void close_timerfd(int timeerfd,int epollfd)
{
close(timeerfd);
close(epollfd);
}
#ifndef __TIMER_SDK__
#define __TIMER_SDK__
#include <sys/timerfd.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/epoll.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
/*
*功能描述:创建基于timerfd的高精度定时器
*此函数注册之后就会循环阻塞在函数指针所指的p函数处
*用法推荐在线程中开此定时器,可以循环阻塞所要执行的p指针函数
*int thread_func(int)
*{
* printf("thread_func\n");
*}
*void *thread(void *arg)
*{
* int time;
* int epoll;
* create_tick_timer(100,100,thread_func,time,epoll);
*}
*@param timeout 超时时间单位ms
*@param period 分频时间单位ms
*@param p 希望执行的函数,自己在内部定义
*@param timerfd 定时器返回的fd
*@param epollfd epoll返回的fd
*@return 0
*/
int create_tick_timer(int32_t timeout,int32_t period,int (*p)(int value),int& timerfd,int& epollfd);
void close_timerfd(int timeerfd,int epollid);
void print_elapsed_time(void);
#endif
main.c代码如下
#include <sys/timerfd.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/epoll.h>
#include "timer_sdk.h"
#include<pthread.h>
int tick(int)
{
printf("1\n");
}
int tick2(int)
{
printf("2\n");
}
int tick3(int)
{
printf("3\n");
}
void *thread11(void *arg)
{
int time;
int epoll;
while(1)
{
create_tick_timer(100,100,tick,time,epoll);
}
}
void *thread22(void *arg)
{
int time;
int epoll;
while(1)
{
create_tick_timer(100,100,tick2,time,epoll);
}
}
void *thread33(void *arg)
{
int time;
int epoll;
while(1)
{
create_tick_timer(100,100,tick3,time,epoll);
}
}
int main(void)
{
pthread_t thread1;
pthread_t thread2;
pthread_t thread3;
pthread_create(&thread1, NULL, &thread11, NULL);
pthread_create(&thread2, NULL, &thread22, NULL);
pthread_create(&thread3, NULL, &thread33, NULL);
pthread_detach(thread1);
pthread_detach(thread2);
pthread_detach(thread3);
while (1)
{
/* code */
}
return 0;
}