首页 > 系统相关 >Linux下C++实现一个定时器

Linux下C++实现一个定时器

时间:2023-05-29 16:55:17浏览次数:36  
标签:定时器 timeout int Timer C++ timerfd Linux include

要在Linux下实现一个定时器,可以使用以下两种方法:

使用系统提供的定时器API

Linux系统提供了一些定时器API,如setitimer、timer_create、timer_gettime等,可以使用这些API来实现定时器。以setitimer为例,可以按照以下步骤来使用:
1.定义一个itimerval结构体变量,该结构体包含定时器的初始值和定时器到期后的动作。
2.使用setitimer函数启动定时器,该函数接受一个定时器类型参数和一个itimerval结构体参数。
3.通过SIGALRM信号来处理定时器到期后的动作,需要安装一个SIGALRM信号的处理函数。
代码如下:

#pragma once
#include <sys/timerfd.h>

#include <atomic>
#include <chrono>
#include <ctime>
#include <functional>
#include <thread>

namespace pickup {

class Timer {
 public:
  using TimerfdCallBack = std::function<void()>;
  /**
   * Create and start a timer
   * @param timeout  Timeout in milliseconds before @p cb is called, zero disarms timer
   * @param period   For periodic timers this is the period time that @p timeout is reset to
   * @param cb       Callback function
   *
   * Note, the @p timeout value must be non-zero.  Setting it to zero
   * disarms the timer.  This is the behavior of the underlying Linux
   * function [timerfd_settimer(2)](https://man7.org/linux/man-pages/man2/timerfd_settime.2.html)
   *
   */
  Timer(int timeout, int period, TimerfdCallBack&& cb);
  ~Timer();

  void start();
  void stop();
  bool isRunning() const { return is_running_; }
  int getFd() const { return timerfd_; }

 private:
  int createTimerfd();
  bool setTimer(int timeout, int period);
  void threadFunc();
  void handleRead();

 private:
  // 定时器的起始时间
  int timeout_;
  // 定时器的间隔时间
  int period_;
  // 定时器文件描述符
  int timerfd_;
  // 回调函数
  TimerfdCallBack callback_;
  // 定时器工作线程
  std::thread thread_;
  // 是否运行中
  std::atomic<bool> is_running_;
};

};  // namespace pickup

#include "pickup/timer/Timer.h"

#include <errno.h>
#include <string.h>
#include <sys/poll.h>
#include <unistd.h>

namespace pickup {

static void msec2tspec(int msec, struct timespec* ts) {
  if (msec > 0) {
    ts->tv_sec = msec / 1000;
    ts->tv_nsec = (msec % 1000) * 1000000;
  } else {
    ts->tv_sec = 0;
    ts->tv_nsec = 0;
  }
}

Timer::Timer(int timeout, int period, TimerfdCallBack&& cb)
    : timeout_(timeout), period_(period), timerfd_(createTimerfd()), callback_(cb), is_running_(false) {}

Timer::~Timer() {
  close(timerfd_);
  timerfd_ = -1;
}

void Timer::start() {
  if (is_running_) return;
  if (!setTimer(timeout_, period_)) return;

  is_running_ = true;
  thread_ = std::thread(&Timer::threadFunc, this);
}

void Timer::stop() {
  if (!is_running_) return;
  is_running_ = false;
  if (thread_.joinable()) {
    thread_.join();
  }
}

void Timer::threadFunc() {
  int timeout = 5000;  // 超时时间(单位:毫秒)
  struct pollfd pfd;
  bzero(&pfd, sizeof(pfd));
  pfd.fd = timerfd_;
  pfd.events = POLLIN;
  while (is_running_) {
    int nready = poll(&pfd, 1, timeout);
    if (nready < 0) {
      if (errno == EINTR) {
        continue;
      } else {
        perror("poll() failed");
        break;
      }
    } else if (0 == nready) {
      printf("poll() timed out.\n");
      continue;
    } else {
      if (pfd.events & POLLIN) {
        // 先读取fd中的数据
        handleRead();
        // 再调用回调函数
        callback_();
      }
    }
  }
}

int Timer::createTimerfd() {
  int timerfd = timerfd_create(CLOCK_REALTIME, 0);
  if (-1 == timerfd) {
    perror("timerfd_create");
  }

  return timerfd;
}

bool Timer::setTimer(int timeout, int period) {
  struct itimerspec time;
  msec2tspec(timeout, &time.it_value);
  msec2tspec(period, &time.it_interval);
  int ret = timerfd_settime(timerfd_, 0, &time, NULL);
  if (-1 == ret) {
    perror("timerfd_settime");
    return false;
  }

  return true;
}

void Timer::handleRead() {
  uint64_t expirations = 0;
  ssize_t result = read(timerfd_, &expirations, sizeof(expirations));
  if (result == -1) {
    perror("timerfd read");
  }
}

}  // namespace pickup

使用C++11提供的std::thread和std::chrono库

C++11提供了std::thread和std::chrono库,可以使用这些库来实现定时器。具体步骤如下:
1.创建一个std::thread对象,该对象将执行一个定时器函数。
2.在定时器函数中,使用std::chrono::steady_clock来获取当前时间和定时器开始时间的差值,判断是否到达定时器到期时间。
3.如果到达定时器到期时间,则执行定时器动作,否则继续等待。
需要注意的是,这种方法需要在定时器函数中使用while循环来不断检测定时器是否到期,可能会对系统资源造成一定的负担。

标签:定时器,timeout,int,Timer,C++,timerfd,Linux,include
From: https://www.cnblogs.com/sunwenqi/p/17440938.html

相关文章

  • linux系统/dev/mapper/centos-root目录被占满的解决方式
    1、查看虚拟机磁盘使用情况df-h 可以看到/dev/mapper/centos-root已经快满了,这时候就算启动hdfs,也会是强制性的进入安全模式,不让写数据2、查看哪个目录占用过高使用du-h-x--max-depth=1查看哪个目录占用过高,对于过高目录中的内容适当删减腾出一些空间cd/&&du-h......
  • 转载-奇小葩-linux性能工具--ftrace框架
    原文链接:https://blog.csdn.net/u012489236/article/details/119494200 对于ftrace架构,主要来了解下内核是如何实现的,其主要包括如下内容:ringbuffer的原理和代码分析tracer(function、function_graph、irq_off)原理和代码分析traceevent1.ringBufferRingbuffer是......
  • linux常用指令(拷贝移动命令)
    (1).cp--复制cphello.txtitcast/--将hello.txt复制到itcast目录中cphello.txt./hi.txt--将hello.txt复制到当前目录,并改名为hi.txtcp-ritcast/./itheima/--将itcast目录和目录下所有文件复制到itheima目录下cp-ritcast/*./itheima/--将itcas......
  • C和C++的性能调优工具
    以下是C和C++的性能调优工具,包含工具介绍和链接:Valgrind:一款非常流行的内存调试和性能分析工具,可以检测内存泄漏、死锁等问题,并提供CPU性能分析工具。它可以跟踪程序中的所有内存分配和释放操作,并在程序执行时给出详细的报告。Valgrind是一个开源工具,支持Linux和MacOS等操......
  • c++ 模版元编程-00
    本系列文章从零开始介绍C++模版元编程,需要有C++基础。函数模版template<typenameT>Tadd(Tconsta,Tconstb){returna+b;}autoa=add(42,21);autod=add<double>(41.0,21);//无法自动推导类型的时候可以显示的指定类型类模版template<typenameT>......
  • Linux防火墙
    firewalld防火墙防火墙命令#查看状态firewall-cmd--state#查看防火墙规则firewall-cmd--list-all#查看已打开的端口firewall-cmd--list-ports#查询端口是否开放firewall-cmd--query-port=8080/tcp#修改配置后要重新加载防火墙规则firewall-cmd--reload配置......
  • C++-条件变量/互斥锁/lock_guard
    条件变量参考C++Reference对于条件变量的解释和例程:https://en.cppreference.com/w/cpp/thread/condition_variable条件变量和互斥锁一般结合使用。因为线程处于等待状态中,一般需要查看一个全局变量或共享的变量的状态,来决定是否停止等待继续运行程序。对于此全局变量,必须要......
  • vm -版本 16.2.3 - 将win10 指定磁盘文件夹挂载为linux【centOS 7】的共享磁盘
    1.vm配置win10磁盘指定文件夹为共享文件夹, 16.2.3版本不需要安装vm-tools 2.在linux开启共享文件夹执行指令sudovmhgfs-fuse.host://mnt/hgfs-osubtype=vmhgfs-fuse,allow_other如果报错这是因为 /mnt/hgfs 文件夹已经存在不需要理会,已经开启共享了在  /......
  • linux - 更新阿里的镜像源 -记录
    可能需要安装wgetyuminstallwget更新阿里的数据源1、yum源进行备份进入到yum源的配置文件中执行命令如下:cd/etc/yum.repos.d将yum源进行备份:mvCentos-Base.repoCentos-Base.repo.bak2、获取阿里的yum源配置文件执行命令:wget-OCentos-Base.repohttp://mirrors.ali......
  • Linux install vim errors All In One
    LinuxinstallvimerrorsAllInOneVimerrors❌RaspberryPi安装vim解压缩时候卡住了,手动中断了terminal,再次SSH连接时候,出现一下错误信息!pi@raspberrypi:~$sudoapt-getinstallvimE:无法获得锁/var/lib/dpkg/lock-frontend。锁正由进程11246(apt-get)持有......