You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++周期性定时器实现:线程安全停止问题求助

C++线程安全定时器实现方案

针对你遇到的定时器停止阻塞、线程安全问题,以下是修正后的完整实现及关键说明:

核心问题分析

  1. 非线程安全的状态变量:原Activated是普通bool,多线程读写会触发未定义行为(编译器可能优化读取,导致线程无法感知状态变化)。
  2. 阻塞式线程管理:原scheduler若直接调用thread::join会卡死主线程,无法触发后续停止操作。
  3. 无法及时响应停止信号:单纯用sleep_for会让定时器线程在等待周期内无法感知停止指令,必须等待周期结束才能退出。

修正后的定时器类实现

#pragma once

#ifndef __MyTimer_h__
#define __MyTimer_h__

#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <functional>

template <typename Cback>
class MyTimer {
public:
    MyTimer() = delete;
    MyTimer(Cback cb, int secs);
    ~MyTimer();

    // 禁用拷贝(线程不可拷贝)
    MyTimer(const MyTimer&) = delete;
    MyTimer& operator=(const MyTimer&) = delete;

    void start();  // 启动定时器线程
    void stop();   // 安全停止定时器

private:
    void timer_loop();  // 定时器线程核心循环

    bool activated_;
    Cback callback_;
    int duration_secs_;
    std::thread timer_thread_;
    std::mutex mtx_;
    std::condition_variable cv_;
};

template <typename Cback>
MyTimer<Cback>::MyTimer(Cback cb, int secs)
    : callback_(std::move(cb)), duration_secs_(secs), activated_(false) {}

template <typename Cback>
MyTimer<Cback>::~MyTimer() {
    stop(); // 析构时自动停止线程,避免资源泄漏
}

template <typename Cback>
void MyTimer<Cback>::start() {
    std::lock_guard<std::mutex> lock(mtx_);
    if (!activated_ && !timer_thread_.joinable()) {
        activated_ = true;
        timer_thread_ = std::thread(&MyTimer::timer_loop, this);
    }
}

template <typename Cback>
void MyTimer<Cback>::stop() {
    {
        std::lock_guard<std::mutex> lock(mtx_);
        if (!activated_) return;
        activated_ = false;
    }
    cv_.notify_one(); // 唤醒等待中的定时器线程
    if (timer_thread_.joinable()) {
        timer_thread_.join(); // 等待线程安全退出
    }
}

template <typename Cback>
void MyTimer<Cback>::timer_loop() {
    std::unique_lock<std::mutex> lock(mtx_);
    while (activated_) {
        // 临时解锁,避免回调执行时持有锁影响stop响应
        lock.unlock();
        callback_();
        lock.lock();

        // 等待周期或被stop唤醒,避免无意义的阻塞
        cv_.wait_for(lock, std::chrono::seconds(duration_secs_),
                     [this]() { return !activated_; });
    }
}

#endif

修正后的主函数

#include <iostream>
#include <memory>
#include <chrono>
#include <iomanip>

void printcurrenttime() {
    auto now = std::chrono::system_clock::now();
    std::time_t now_time = std::chrono::system_clock::to_time_t(now);
    std::cout << " " << std::ctime(&now_time);
}

void callbackfunc() {
    std::cout << "callback function called at";
    printcurrenttime();
}

int main() {
    std::cout << "\nmain function called at";
    printcurrenttime();

    std::unique_ptr<MyTimer<std::function<void(void)>>> timer(
        new MyTimer<std::function<void(void)>>(callbackfunc, 2));
    
    timer->start(); // 启动定时器,主线程继续执行

    std::this_thread::sleep_for(std::chrono::seconds(20));
    std::cout << "\nStopping timer...\n";
    timer->stop(); // 安全停止定时器

    std::cout << "\nMain thread exiting\n";
    return 0;
}

关键实现细节

  1. 线程安全状态控制:用std::mutex保护activated_变量,确保主线程和定时器线程的读写操作互斥,避免数据竞争。
  2. 即时停止响应:用std::condition_variable::wait_for替代单纯的sleep_for,调用stop()时会立即唤醒定时器线程,无需等待剩余周期。
  3. 非阻塞启动:start()仅启动线程就返回,主线程可正常执行后续逻辑,直到需要停止时调用stop()等待线程退出。
  4. 安全析构:析构函数自动调用stop(),确保对象销毁时线程已完全退出,防止悬空线程。

内容的提问来源于stack exchange,提问作者Tej Ravi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 19:32:04