C++定时器实现和时间轮介绍

C++ 定时器实现和时间轮介绍

定时器是计算机系统中非常常见的一种机制,可以用来在一定时间间隔后执行某些操作,或在特定时间点执行某些操作。在 C++ 编程中,我们可以使用定时器来进行任务调度等操作。其中,时间轮是一种常见的定时器实现方式,下面将详细介绍时间轮的概念和实现,以及如何在 C++ 中进行定时器的编写。

什么是时间轮?

时间轮是一种基本的定时器实现方法,它将时间线划分成多个区间,每个区间代表一个时间间隔,每个槽位代表了一个定时任务。时间轮中还有一个指针,指向当前正在执行的槽位,每经过一个时间间隔,指针会向后移动一个槽位。当指针指向某个槽位时,就会执行该槽位中的定时任务。

时间轮的优点在于,可以快速定位到需要执行的定时任务,并且可以处理高并发的情况,即可以同时管理多个定时任务。

时间轮的实现方法

时间轮的实现方法相对简单,可以使用一个循环数组来存储各个槽位,使用一个指针来指向当前执行的槽位,每经过一个时间间隔,指针就会向后移动一个槽位。当执行到某个槽位时,就会执行该槽位中的所有定时任务。

具体实现可以分为以下步骤:

  1. 创建时间轮对象,存储循环数组和指针
  2. 向时间轮中添加定时任务,计算定时任务在时间轮中对应的槽位,将定时任务插入槽位
  3. 启动时间轮,开始执行定时任务
  4. 每经过一个时间间隔,指针向后移动一个槽位,并执行该槽位中的所有定时任务
  5. 当时间轮执行完一圈时,重新回到第一个槽位,继续执行定时任务,直到时间轮被停止

以下是使用 C++ 实现时间轮的代码示例:

#include <iostream>
#include <vector>
#include <functional>
#include <chrono>
#include <thread>

using namespace std::chrono_literals;

class Timer {
public:
    Timer(size_t wheelSize, size_t tickDuration)
        : m_wheelSize(wheelSize), m_tickDuration(tickDuration), m_currentTick(0), m_wheel(wheelSize), m_stop(false)
    {
        m_wheel[0].resize(0xffffffffu / wheelSize + 1);  // 根据 wheelSize 计算每个槽位能包含的最大超时时间
    }

    void start()
    {
        m_stop = false;
        m_ticksThread = std::thread([this] {
            while (!m_stop) {
                std::this_thread::sleep_for(m_tickDuration);
                onTick();
            }
        });
    }

    void stop()
    {
        m_stop = true;
        if (m_ticksThread.joinable()) {
            m_ticksThread.join();
        }
    }

    template <typename FuncType>
    void addTimer(size_t timeoutMs, FuncType&& func)
    {
        if (m_stop) {
            return;
        }
        auto wheelIdx = (m_currentTick + (timeoutMs / m_tickDuration)) % m_wheelSize;  // 获取任务应该插入的槽位
        auto& bucket = m_wheel[wheelIdx];
        bucket.emplace_back(std::forward<FuncType>(func));
    }

private:
    void onTick()
    {
        auto& bucket = m_wheel[m_currentTick % m_wheelSize];            
        for (auto& func : bucket) {  // 执行当前槽位中的任务
            func();
        }
        bucket.clear();
        m_currentTick = (m_currentTick + 1) % m_wheelSize;  // 将时间轮指针向后移动一个槽位
    }

private:
    size_t m_wheelSize;
    size_t m_tickDuration;
    size_t m_currentTick;
    std::vector<std::vector<std::function<void()>>> m_wheel;
    std::thread m_ticksThread;
    bool m_stop;
};

int main()
{
    Timer timer(60, 100ms);  // 创建时间轮,60 个槽位,每个槽位 100 ms
    timer.start();  // 启动时间轮

    for (int i = 0; i < 1000; i++) {  // 添加 1000 个定时任务
        timer.addTimer(i * 10, [i] {
            std::cout << "Task " << i << " is executed at " << std::chrono::system_clock::now().time_since_epoch().count() << std::endl;
        });
    }

    std::this_thread::sleep_for(15s);  // 等待 15s,让时间轮执行完毕

    timer.stop();  // 停止时间轮

    return 0;
}

使用 boost 实现定时器

除了手动实现时间轮,我们还可以使用 boost 库提供的定时器组件来实现定时器。下面是使用 boost 定时器组件实现定时器的代码示例:

#include <iostream>
#include <boost/asio.hpp>

using namespace boost::asio;

int main()
{
    io_service io;
    deadline_timer t(io, boost::posix_time::seconds(5));  // 创建一个定时器,5s 后触发

    t.wait();  // 等待定时器触发

    std::cout << "Timer is expired." << std::endl;

    return 0;
}

上面的代码创建了一个定时器,5s 后触发,使用 wait 函数等待定时器触发。需要注意的是,使用 boost 定时器组件时需要注意线程安全性问题。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++定时器实现和时间轮介绍 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • 深入理解c语言数组

    深入理解C语言数组 什么是数组 数组是一种数据结构,它是由相同类型的元素所组成的序列。 在C语言中,数组是由相同类型的元素在内存中连续存储所组成的。数组的下标是从0开始的非负整数,用于访问数组中的元素。数组的大小是在声明时指定的,一旦确定大小就不能改变。 数组的声明 C语言数组的声明格式如下: type arrayName[arraySize]; 其中,ty…

    C 2023年5月24日
    00
  • 如何判断一个整数的二进制中有多少个1

    要判断一个整数的二进制中有多少个1,可以采用以下两种方法: 方法一:遍历每一位对于二进制数字,可以通过不断取模和除法,得到每一位的数字,然后判断当前位是否为1。具体步骤如下: 定义一个计数器counts,用于记录1的个数 对于整数num,不断进行模2运算,得到二进制数中当前位的数字,记为temp 如果temp为1,则counts加1 对num进行除2运算,向…

    C 2023年5月23日
    00
  • C语言菜鸟基础教程之判断

    下面是针对“C语言菜鸟基础教程之判断”进行详细讲解的完整攻略。 什么是判断语句? 判断语句是编程中非常重要的控制语句之一,它能够根据指定条件的真假来完成不同的操作。在C语言中,判断语句主要有两种:if语句和switch语句。 if语句 if语句是C语言中最为基础的判断语句,它的基本语法如下: if (condition) { statement1; } el…

    C 2023年5月22日
    00
  • js如何获取object类型里的键值

    获取object类型里的键值可以使用JavaScript语言提供的两种方式:点运算符(.)和方括号([])。 点运算符(.) 点运算符是一种简单直接获取对象属性的方法,使用点运算符需要知道对象中属性的名称。例如,如果要获取下面这个对象中name属性的值,可以这样写: const obj = { name: "张三", age: 18 };…

    C 2023年5月22日
    00
  • Javascript实用方法之json合并的场景分析

    Javascript实用方法之json合并的场景分析 在开发中,JSON合并是一项非常常见的需求。本篇攻略将介绍典型的JSON合并场景及其解决方案。 场景分析 假设有两个JSON对象,分别为: let object1 = { name: ‘John’, age: 25, location: { city: ‘New York’, country: ‘USA’…

    C 2023年5月23日
    00
  • C++11各种锁的具体使用

    C++11各种锁的具体使用 在多线程编程时,锁是常用的线程同步机制之一。C++11中提供了多种不同的锁类型,用于处理不同的并发情况,本文将详细介绍这些锁的用法。 1、互斥锁(std::mutex) 使用互斥锁可以实现对共享资源的互斥访问。 #include <iostream> #include <mutex> #include &l…

    C 2023年5月22日
    00
  • 基于C++编写一个键盘提示音程序

    关于基于C++编写一个键盘提示音程序的攻略,我将为您提供以下完整的指导: 步骤一:了解键盘输入的基础知识 在编写键盘提示音的程序之前,我们需要了解一些基础概念: 键盘布局:键盘上每一个按键的位置; 扫描码:键盘上每一个按键都有一个与之对应的扫描码,用于唯一地识别每一个按键; ASCII码:每一个扫描码都对应了一个ASCII码,用于标示按键所对应的字符。 步骤…

    C 2023年5月23日
    00
  • Rust 能够取代 C 语言吗

    可以开始讨论“Rust能否取代C语言”这个话题了。对于这个问题,我们可以从以下几个方面入手: 1. 性能表现 C语言因历史悠久和底层的特性而被广泛使用。因为C语言非常接近机器硬件,它能够直接访问内存和硬件资源,因此具有非常高的性能。但C语言在安全方面较差,容易出现内存泄漏和指针错误等问题。 Rust语言是一个新型的系统编程语言,它被设计为具有高性能和内存安全…

    C 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部