Linux下 timerfd创建定时器并使用 epoll 监听

3 篇文章 2 订阅
2 篇文章 0 订阅


介绍: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(&current, 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(&current, 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;
}

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用EPOLL监听UDP接收需要以下步骤: 1. 创建UDP套接字并绑定端口号 2. 创建epoll实例,将UDP套接字添加到epoll实例中 3. 调用epoll_wait()函数进行监听事件 4. 如果epoll_wait()返回UDP套接字有事件发生,则调用recvfrom()函数接收UDP数据包 以下是一个简单的示例代码: ``` #include <sys/epoll.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define MAX_EVENTS 10 int main() { int sockfd = socket(AF_INET, SOCK_DGRAM, 0); struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(8080); bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)); int epfd = epoll_create(MAX_EVENTS); struct epoll_event event, events[MAX_EVENTS]; event.data.fd = sockfd; event.events = EPOLLIN; epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event); while (1) { int n = epoll_wait(epfd, events, MAX_EVENTS, -1); for (int i = 0; i < n; i++) { if (events[i].data.fd == sockfd) { char buffer[1024]; struct sockaddr_in client_addr; socklen_t client_len = sizeof(client_addr); int len = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_addr, &client_len); printf("Received %d bytes from %s:%d\n", len, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); } } } close(epfd); close(sockfd); return 0; } ``` 在这个示例代码中,我们创建了一个UDP套接字,并绑定了端口号8080。然后,我们创建了一个epoll实例,并将UDP套接字添加到epoll实例中。在主循环中,我们调用epoll_wait()函数进行监听事件,如果UDP套接字有事件发生(EPOLLIN),则调用recvfrom()函数接收UDP数据包。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值