基于C++11的简单定时器(SimpleTimer)

SimpleTimer 是一个跨平台的轻量级定时器类,支持在后台线程中定期执行任务,适用于需要定时执行任务的场景。它支持暂停、恢复、修改时间间隔等功能,且不依赖任何第三方库,仅使用 C++11 标准库实现。

特性

  • 跨平台支持:在多个平台上(如 Windows、Linux、macOS)均可运行,基于 C++11 标准库实现。
  • 线程安全:内部使用 std::threadstd::condition_variable,保证线程安全。
  • 灵活的时间间隔:支持使用 std::chrono::duration 设置任意时间单位(分钟、秒、毫秒等)。
  • 支持多种执行模式:包括单次执行(one-shot)和重复执行(周期性)。
  • 控制功能完善:支持暂停、恢复、重启定时器,支持动态修改时间间隔。
  • 时间精度良好:定时器精度取决于系统时钟,通常为毫秒级别。
  • 自动资源管理SimpleTimer 对象析构时会自动停止定时器,即使忘记调用 stop 也能确保资源正确释放。

使用方式

simple_timer.h 文件复制到你的项目目录中,在源码中引入即可使用:

1
#include "simple_timer.h"

在 POSIX 系统(如 Linux、macOS)中,std::thread 基于 pthread 实现,因此需要在编译时加上 -lpthread 链接选项。

示例代码

以下是一个完整的示例代码,展示了如何使用 SimpleTimer 类:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include "simple_timer.h"
#include <iostream>

int main() {
    SimpleTimer timer(std::chrono::seconds(1));  // 定时器间隔为1秒,重复执行任务

    timer.start([]() {
        std::cout << "定时器任务执行!" << std::endl;
    });

    std::this_thread::sleep_for(std::chrono::seconds(5));  // 等待5秒

    timer.pause();  // 暂停定时器
    std::cout << "定时器已暂停..." << std::endl;

    std::this_thread::sleep_for(std::chrono::seconds(3));  // 等待3秒

    timer.resume();  // 恢复定时器
    std::cout << "定时器已恢复..." << std::endl;

    std::this_thread::sleep_for(std::chrono::seconds(5));  // 等待5秒

    timer.stop();  // 停止定时器
    std::cout << "定时器已停止" << std::endl;

    return 0;
}

代码实现:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
/**
 * @author: abin
 * @date: 2025-04-12
 * @license: MIT
 * @repository: https://github.com/abin-z/SimpleTimer
 */
#ifndef SIMPLE_TIMER_H
#define SIMPLE_TIMER_H

#include <atomic>
#include <chrono>
#include <condition_variable>
#include <cstdio>
#include <mutex>
#include <thread>

/**
 * @brief 使用 std::condition_variable 的 wait_until 方法 (也可以使用wait_for方法, 但是会累计误差)
 * 函数原型:
 * cv.wait_until(lock, time_point, predicate);
 *
 * wait_until 的行为:
 * - wait_until 方法的作用是让当前线程在指定的时间点之前等待, 直到条件变量被通知或者超时
 * - 进入等待前会先检查 predicate() 的值.
 * - 如果 predicate() 在进入等待前立即为 true, 则直接返回 true, 不会进入等待状态
 * - 如果 predicate() 为 false, 则进入等待状态, 直到 time_point 到达
 * - 如果在 time_point 到达前 `notify_*` 被调用, 并且此时 predicate() 为 true, 则唤醒并返回 true
 * - 如果在 time_point 到达前 `notify_*` 被调用, 但此时 predicate() 为 false, 则继续等待(可能是虚假唤醒)
 * - 如果直到 time_point 到达时 predicate() 仍为 false, 返回 false(表示超时)
 *
 * 简要来说:
 * - `wait_until` 返回 true 表示条件变量被唤醒并且条件成立
 * - `wait_until` 返回 false 表示已超时, 且条件仍未满足(即超时触发任务)
 */

/// @brief A simple timer class
class SimpleTimer
{
  using clock = std::chrono::steady_clock;  // 单调时钟, 不受系统时间变化影响
 public:
  /// @brief Timer state
  enum class State : unsigned char
  {
    Stopped = 0,  // 停止
    Running = 1,  // 运行中
    Paused = 2,   // 暂停
  };

  /// @brief Constructs a SimpleTimer with a given duration
  /// @tparam Rep Duration representation type (e.g., int, long)
  /// @tparam Period Duration unit type (e.g., seconds, milliseconds)
  /// @param interval The time interval
  /// @param one_shot If true, the timer will only trigger once
  template <typename Rep, typename Period>
  SimpleTimer(std::chrono::duration<Rep, Period> interval, bool one_shot = false) :
    interval_(interval), one_shot_(one_shot), state_(State::Stopped)
  {
  }

  /// @brief Constructs a SimpleTimer with a millisecond interval
  /// @param milliseconds The time interval in milliseconds
  /// @param one_shot If true, the timer will only trigger once
  explicit SimpleTimer(long long milliseconds, bool one_shot = false) :
    SimpleTimer(std::chrono::milliseconds(milliseconds), one_shot)  // 代理到主构造函数
  {
  }

  /// @brief Constructs a SimpleTimer with a default interval of 10 seconds
  /// @param one_shot If true, the timer will only trigger once
  SimpleTimer(bool one_shot = false) : SimpleTimer(std::chrono::seconds(10), one_shot)  // 默认间隔为10秒
  {
  }

  /// @brief Destructor. Automatically stops the timer to clean up resources.
  ~SimpleTimer()
  {
    stop();
  }

  // Delete copy constructor and copy assignment operator
  SimpleTimer(const SimpleTimer&) = delete;
  SimpleTimer& operator=(const SimpleTimer&) = delete;

  // Delete move constructor and move assignment operator
  SimpleTimer(SimpleTimer&&) = delete;
  SimpleTimer& operator=(SimpleTimer&&) = delete;

  /// @brief Starts the timer
  /// @tparam Func Callable object type
  /// @param f A callable object to be executed when the timer expires
  /// @note The timer task will be executed in a new thread
  template <typename Func>
  void start(Func&& f)
  {
    stop();                                        // 确保没有其他线程在运行(替换旧任务)
    state_ = State::Running;                       // 设置状态为运行中
    auto task = std::move(std::forward<Func>(f));  // 完美转发后再 move, 提高效率
    // 使用 std::thread 创建一个新的线程来执行定时器任务
    thread_ = std::thread([this, task]() mutable {
      std::unique_lock<std::mutex> lock(mutex_);
      auto next_time = clock::now() + interval_;
      while (true)
      {
        if (state_ == State::Stopped)
        {
          break;
        }

        while (state_ == State::Paused)
        {
          cv_.wait(lock, [this]() { return state_ != State::Paused; });
          next_time = clock::now() + interval_;  // 重新计算下一次触发时间
        }

        if (cv_.wait_until(lock, next_time, [this]() { return state_ != State::Running || interval_changed_; }))
        {
          if (interval_changed_)  // interval_修改后立即使用新间隔
          {
            next_time = clock::now() + interval_;
            interval_changed_ = false;
          }
          continue;  // 若状态不是 Running, 继续循环判断; 若是 interval_ 被修改, 则更新 next_time 并立即跳过等待
        }

        lock.unlock();
        // Timer 内部处理异常, 执行task遇到异常后直接停止timer
        try
        {
          task();  // 执行任务
        }
        catch (const std::exception& e)
        {
          state_ = State::Stopped;  // 出现异常时停止定时器 (不能调用stop()会死锁)
          std::fprintf(stderr, "[SimpleTimer] Exception: %s\n", e.what());
        }
        catch (...)
        {
          state_ = State::Stopped;  // 出现异常时停止定时器
          std::fprintf(stderr, "[SimpleTimer] Unknown exception occurred.\n");
        }
        lock.lock();

        if (one_shot_)
        {
          state_ = State::Stopped;
          break;
        }

        next_time += interval_;  // 精确推进时间点, 避免偏差
      }
    });
  }

  /// @brief Restarts the timer
  /// @tparam Func Callable object type
  /// @param f A callable object to be executed when the timer expires
  template <typename Func>
  void restart(Func&& f)
  {
    stop();
    start(std::forward<Func>(f));
  }

  /// @brief Stops the timer; waits for the current task to complete before fully stopping
  /// @note This method may block until the running task completes.
  void stop()
  {
    state_ = State::Stopped;
    cv_.notify_all();  // 唤醒等待的线程
    if (thread_.joinable())
    {
      thread_.join();  // 等待线程结束
    }
  }

  /// @brief Pauses the timer
  void pause()
  {
    if (state_ == State::Running)
    {
      state_ = State::Paused;
    }
  }

  /// @brief Resumes the timer if it was paused
  void resume()
  {
    if (state_ == State::Paused)
    {
      state_ = State::Running;
      cv_.notify_all();  // 唤醒正在等待的线程
    }
  }

  /// @brief Gets the current timer interval
  /// @return The interval in milliseconds
  std::chrono::milliseconds interval() const
  {
    return std::chrono::duration_cast<std::chrono::milliseconds>(interval_);
  }

  /// @brief Sets a new timer interval, takes effect immediately
  /// @param new_interval A duration representing the new interval
  template <typename Rep, typename Period>
  void set_interval(std::chrono::duration<Rep, Period> new_interval)
  {
    {
      std::lock_guard<std::mutex> lock(mutex_);
      interval_ = new_interval;
      interval_changed_ = true;  // 标记为已改变
    }
    cv_.notify_all();  // 确保线程能获取到新的时间间隔
  }

  /// @brief Sets a new timer interval, takes effect immediately
  /// @param milliseconds New interval in milliseconds
  void set_interval(long long milliseconds)
  {
    set_interval(std::chrono::milliseconds(milliseconds));
  }

  /// @brief Gets the current state of the timer
  /// @return The state of the timer
  State state() const
  {
    return state_;
  }
  /// @brief Checks if the timer is currently running
  /// @return true if running, false otherwise
  bool is_running() const
  {
    return state_ == State::Running;
  }
  /// @brief Checks if the timer is currently paused
  /// @return true if paused, false otherwise
  bool is_paused() const
  {
    return state_ == State::Paused;
  }
  /// @brief Checks if the timer is currently stopped
  /// @return true if stopped, false otherwise
  bool is_stopped() const
  {
    return state_ == State::Stopped;
  }

 private:
  // 定时器间隔, 默认10秒
  clock::duration interval_ = std::chrono::seconds(10);
  bool interval_changed_ = false;  // 时间间隔是否被修改过
  bool one_shot_ = false;          // 是否只触发一次
  std::atomic<State> state_;       // 定时器状态
  std::thread thread_;             // 定时器线程
  std::mutex mutex_;               // 互斥锁, 确保线程安全
  std::condition_variable cv_;     // 条件变量, 用于暂停和恢复
};

#endif  // SIMPLE_TIMER_H
本文采用 CC BY-NC-SA 4.0 协议进行许可,转载请注明出处。
最后更新于 2025-05-30
使用 Hugo 构建
主题 StackJimmy 设计