0804-----Linux基础----------定时器之 timerfd

1.timerfd 的基本用法

  1.1 timerfd 系列的定时器采用的不是信号,而是 fd 可读,常用的函数有 timerfd_create 、timerfd_settime 和 timerfd_gettime, 这些函数的功能和用法也比较浅显,这里用一个简单的例子(1.2)来说明其用法,create 参数中 CLOCK_REALTIME 是一个相对时间,当系统时间被更改时会进行调整,还有一个参数CLOCK_MONOTONIC,它是绝对时间,更改系统时间对它没有影响,这里flags一般设为0,前面说到,定时器到期表现为 timerfd 可读,因此就可以把该fd加入到IO复用模型当中去(1.3)。

  1.2 创建一个定时器,设置好时间间隔结构体的参数,开启定时器,这样一个定时器就可以工作了,但是这里要注意,timerfd 定时器到期时表现为该 fd 有数据可读,因此一旦到时,一定要把数据 read 出去,不然定时器就无法正常工作。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/timerfd.h>
#define ERR_EXIT(m)     do {         perror(m);        exit(EXIT_FAILURE);    }while(0)
/*
 * 定时器timerfd的基础用法
 */

int main(int argc, const char *argv[])
{
    //创建定时器的fd
    int timerfd = timerfd_create(CLOCK_REALTIME, 0);
    if(timerfd == -1)
        ERR_EXIT("timerfd_create");
    //开启定时器,并设置定时器的时间
    struct itimerspec new_value; // const
    memset(&new_value, 0, sizeof new_value);
    new_value.it_value.tv_sec = 5; //初始到期时间
    new_value.it_interval.tv_sec = 1; //之后的间隔时间
    if(timerfd_settime(timerfd, 0, &new_value, NULL) == -1)
        ERR_EXIT("timerfd_settime");

    char buf[1024] = {0};
    int ret;
    while((ret = read(timerfd, buf, sizeof buf)) > 0){
        printf("ret = %d, read data:%s\n", ret, buf); //
    }

    close(timerfd);
    return 0;
}

  1.3 将timer和poll一起使用,timerfd 加入到 poll 的监听数组中,当 timer 到期,poll 就会监听到该 timerfd。这里 poll 采用的是水平触发模式,也就是说对于某 fd 可读,如果不做 read 处理,那么下次会再次返回该 fd,即该 fd一直可读,等待着被读出去,如果不读出去,就一直被触发,那么定时器就没用了。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>
#include <sys/timerfd.h>
#define ERR_EXIT(m)     do {         perror(m);        exit(EXIT_FAILURE);    }while(0)
/*
 * 定时器timerfd 和 epoll 一起使用
 */

int main(int argc, const char *argv[])
{
    //创建定时器的fd
    int timerfd = timerfd_create(CLOCK_REALTIME, 0);
    if(timerfd == -1)
        ERR_EXIT("timerfd_create");
    //开启定时器,并设置定时器的时间
    struct itimerspec new_value; // const
    memset(&new_value, 0, sizeof new_value);
    new_value.it_value.tv_sec = 5; //初始到期时间
    new_value.it_interval.tv_sec = 1; //之后的间隔时间
    if(timerfd_settime(timerfd, 0, &new_value, NULL) == -1)
        ERR_EXIT("timerfd_settime");

    char buf[1024] = {0};
    struct pollfd event[1];
    event[0].fd = timerfd;
    event[0].events = POLLIN;

    while(1){
        int ret =  poll(event, 1, 10000);//等待的最长时间是10s
        if(ret == -1)
            ERR_EXIT("poll");
        else if(ret == 0)
            printf("timeout\n");
        else{
            if(read(timerfd, buf, sizeof buf) == -1) //这里如果不read 会一直被触发
                ERR_EXIT("read");
            printf("foobar....\n");
        }
    }
}

  1.4 一个Timer类,这里把 timerfd 类的函数封装成类,由用户提供定时器到期时要执行的操作(即使用函数回调),这样做的好处,也就是面向对象的好处,对外界提供接口函数,需要时直接用对象调用,更加安全。

#ifndef __TIMER_H__
#define __TIMER_H__

#include "NonCopyable.h"
#include <functional>
#include <sys/timerfd.h>

class Timer : NonCopyable{
    public:
        typedef std::function<void ()> TimerCallback; //定时器回调函数类型
        Timer();
        ~Timer();

        void setTimer(int  init_val, int inter_val); //参数为初始到期时间 和 以后每次的间隔时间
        void setCallback(const TimerCallback &callback);
        void runTimer();

    private:
        int timerfd_;
        struct itimerspec howlong_;
        TimerCallback  callback_; //用户自定义的逻辑
};

#endif  /*__TIMER_H__*/
#include "Timer.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <poll.h>
#include <iostream>
#define ERR_EXIT(m)     do {         perror(m);        exit(EXIT_FAILURE);    }while(0)

Timer::Timer(){
    timerfd_ = timerfd_create(CLOCK_REALTIME, 0);
    if(timerfd_ == -1)
        ERR_EXIT("timer_create");
    memset(&howlong_, 0, sizeof howlong_);
}

Timer::~Timer(){
    close(timerfd_);
}

void Timer:: setTimer(int init_val, int inter_val){ //参数
    howlong_.it_value.tv_sec = init_val;
    howlong_.it_interval.tv_sec = inter_val;
}

void Timer::setCallback(const TimerCallback &callback){
    callback_ = callback;
}

void Timer::runTimer(){
    //开启定时器
    if(timerfd_settime(timerfd_, 0, &howlong_, NULL) == -1)
        ERR_EXIT("timerfd_settime");

    struct pollfd event[1];
    event[0].fd = timerfd_;
    event[0].events = POLLIN;
    char buf[1024];
    int ret;

    while(1){
       ret = poll(event, 1, 1000); //每隔1s 轮询一次
       if(ret == -1)
           ERR_EXIT("poll");
       else if(ret == 0)
           std::cout << "timerout" << std::endl;
       else{
           if(read(timerfd_, buf, sizeof buf)== -1)
               ERR_EXIT("read");
            callback_(); //调用用户逻辑
       }
    }
}

#include "Timer.h"
#include <iostream>
using namespace std;

void func(){
    cout << "hello world" << endl;
}

int main(int argc, const char *argv[])
{
    Timer tm;
    tm.setTimer(3, 1);
    tm.setCallback(func);
    tm.runTimer();
    return 0;
}

2.Timer 和 Thread 类的组合

  2.1 程序编写思路:

    a)把用户逻辑 bind 到 Timer 里面;

    b)把Timer 的 runTimer 方法bind 到 Thread 里面;

    c)也就是说,把 Timer 的操作封装到线程里,执行线程也就是开启定时器。

  2.2 源程序清单

    a)Thread.h Thread.cpp

#ifndef __THREAD_H__
#define __THREAD_H__
#include "NonCopyable.h"
#include <pthread.h>
#include <functional>

class Thread : NonCopyable{
    public:
        typedef std::function<void ()> ThreadCallback;

        Thread();
        explicit Thread(const ThreadCallback &callback);
        ~Thread();

        void setCallback(const ThreadCallback &callback);
        void start();
        void join();

    private:
        static void *thread_func(void *);

        pthread_t tid_;
        ThreadCallback callback_;
        bool isStarted_;

};

#endif  /*__THREAD_H__*/
#include "Thread.h"
Thread::Thread()
    :tid_(-1),
     isStarted_(false)
{
}

Thread::Thread(const ThreadCallback &callback)
    :tid_(-1),
     isStarted_(false),
     callback_(callback)
{
}

Thread::~Thread(){
    if(isStarted_)
        pthread_detach(tid_);
}

void Thread::setCallback(const ThreadCallback &callback){
    callback_ = callback;
}

void Thread::start(){
    isStarted_ = true;
    pthread_create(&tid_, NULL, thread_func, this);
}

void Thread::join(){
    isStarted_ = false;
    pthread_join(tid_, NULL);
}

void *Thread::thread_func(void *arg){
    Thread *pt = static_cast<Thread *>(arg);
    pt->callback_();
    return NULL;
}

    b) test_timer.cpp

#include "Timer.h"
#include "Thread.h"
#include <iostream>
using namespace std;
/*
 * 使用类的组合 Thread 和 Timer 类
 */
class TimerThread{
    public:
        TimerThread();
        void print(); //定时器到期时 执行的函数
        void startTimerThread();
    private:
        Thread thread_;
        Timer timer_;
};

TimerThread::TimerThread(){}

void TimerThread::print(){
    cout << "hello world" << endl;
}

void TimerThread::startTimerThread(){
    timer_.setTimer(3, 1);
    timer_.setCallback(bind(&TimerThread::print, this));

    // 线程类用来封装Timer的操作
    thread_.setCallback(bind(&Timer::runTimer, &timer_));
    thread_.start();
    thread_.join();
}

int main(int argc, const char *argv[])
{
    TimerThread tt;
    tt.startTimerThread();
    return 0;
}

  

0804-----Linux基础----------定时器之 timerfd

时间: 2024-10-12 00:19:50

0804-----Linux基础----------定时器之 timerfd的相关文章

Centos Linux基础入门知识类

Centos Linux基础入门知识类 1.1Linux终端介绍 1.2基本命令的使用:ls.pwd.cd. 1.3 查看系统和BIOS硬件时间. 1.4 Linux如何获得帮助,Linux关机命令:shutdow.init等. 1.5 YUM本地源配置与开机自动挂载光盘 前言: 很多学习Linux的同学或多或少都知道,Linux是一个命令行下的操作系统,因为线上环境基本上不会使用图形化安装,所以该系统基本都是通过命令来完成对系统的操作,本人将为大家介绍一些简单的基础命令. 单词整理: term

【系统知识点】linux基础&优化命令

Xshell上传下载服务器的文件: yum -y install lrzsz sysstat//安装对应软件 sz XXXX//下载 rz XXXX//上传 创建用户: Useradd vrfxie //创建用户 -c comment 指定一段注释性描述. -d 目录 指定用户主目录,如果此目录不存在,则同时使用-m选项,可以创建主目录. -g 用户组 指定用户所属的主用户组. -G 用户组,用户组 指定用户所属的附加组. -s Shell文件 指定用户的登录Shell. #可以设置为/sbin

Linux基础的调优及安全设置

基础的调优及安全设置. a简单优化Linux 1.关闭Selinux [[email protected] selinux]#cd /etc/selinux/ [[email protected] selinux]# sed -i s#SELINUX=enforcing#SELINUX=disabled#g config [[email protected] selinux]# cat config # This file controls the state of SELinux on the

linux基础学习笔记——操作大全

作者:liaoyi 更新时间:2014-6-2 ****************基本操作***************** 关机 shutdown -h now    root用户               init 0              root用户halt      root+一般用户poweroff 重启shutdown -r now    root用户init6     root用户reboot            root+一般用户 注意:1.shutdown 比较灵活,可

Linux基础知识入门

[Linux基础]Linux基础知识入门及常见命令. 前言:最近刚安装了Linux系统, 所以学了一些最基本的操作, 在这里把自己总结的笔记记录在这里. 1,V8:192.168.40.10V1:192.168.40.11Linux ip:192.168.40.128 2,Linux是一个操作系统, 与windows的区别:Linux:图形化界面简单,性能很快,在企业中当做服务器来使用.Windows:图形化界面很炫,性能相对差,大众用户.windows的服务器: windows2003,win

linux基础知识学习-linux架构

硬盘分区: 第一扇区(512bytes): MSR:master boot record (446bytes)主引导分区 partion table:(64bytes)分区表,四个.可以是主分区(primary)或者扩展分区(Extended), 每个表指向磁盘某段区间.最多只有一个扩展分区,扩展分区里面可以扩展多个逻辑分区.其余扇区(柱面(cylinder)):实际存储的地方 linux 中(\etc/fstab):IDE  总线形式不同 (a~d)/dev/hda SATA,SCSI,USB

Linux基础入门学习笔记20135227黄晓妍

学习计时:共24小时 读书:1小时 代码:8小时 作业:3小时 博客:12小时 一.学习目标 1. 能够独立安装Linux操作系统 2. 能够熟练使用Linux系统的基本命令 3. 熟练使用Linux中用户管理命令/系统相关命令/文件目录相关命令/打包压缩相关命令/比较合并相关命令/网络相关命令等 4. 熟练应用“搜索”进行举一反三的学习 二.学习资源 1. 课程资料:https://www.shiyanlou.com/courses/413   实验一,课程邀请码:W7FQKW4Y 2. Li

(转)Linux基础知识学习

Linux基础知识学习 原文:http://blog.csdn.net/ye_wei_yang/article/details/52777499 一.Linux的磁盘分区及目录 Linux的配置是通过修改配置文件来完成. 1.1.Linux磁盘分区 Linux可以将磁盘分为多个分区,每个分区可以被当做一个独立的磁盘使用,磁盘类型:主分区.扩展分区.逻辑分区. 主分区标记为活动,用于操作系统的引导,一块磁盘最多划分4个主分区,主分区存放操作系统的文件或用户数据. 扩展分区:主分区小于4个时才可以划

2017-2018-2 20179204《网络攻防实践》第一周学习总结之linux基础

我在实验楼中学习了Linux基础入门课程,这里做一个学习小结. 第一节 linux系统简介 本节主要介绍了linux是什么.发展历史.重要人物.linux与window的区别以及如何学习linux. 1.什么是linux Linux是一个操作系统,就像Windows(xp,7,8)和 Mac OS.Linux 主要是系统调用和内核那两层.直观地看,操作系统还包含一些在其上运行的应用程序,比如文本编辑器.浏览器.电子邮件等. 2.linux与windows的区别 linux免费或收取少许费用: l