【问题标题】:Need help in implementation of a timer/ticker class in C++在 C++ 中实现计时器/自动收录器类时需要帮助
【发布时间】:2014-07-16 10:50:49
【问题描述】:

在实现具有启动/停止/暂停功能、可分配回调 (onTick) 的代码类时需要帮助,每个间隔跨度在单独的线程上执行。间隔跨度是可指定和可更新的。希望它应该是跨平台的。

这是我的幼稚尝试,但这并不好(start() 中的 while 循环目前正在阻塞,但理想情况下它应该在单独的线程上运行,但我不知道如何实现它)因为我是C++ 多线程模型中的漂亮菜鸟:

#include <cstdint>
#include <functional>
#include <chrono>
#include <thread>
#include <future>

class Ticker {
public:
    typedef std::chrono::duration<int64_t, std::nano> tick_interval_t;
    typedef std::function<void()> on_tick_t;

    Ticker (std::function<void()> onTick, std::chrono::duration<int64_t, std::nano> tickInterval) 
    : _onTick (onTick)
    , _tickInterval (tickInterval)
    , _running (false) {}
    ~Ticker () {}

    void start () {
        if (_running) return;
        _running = true;
        while (_running) {
            std::async( std::launch::async, _onTick );
            std::this_thread::sleep_for( _tickInterval );
        }
    }
    void stop () { _running = false; }

private:
    on_tick_t           _onTick;
    tick_interval_t     _tickInterval;
    bool                _running;
};

我的尝试完全错了,还是非常接近?

【问题讨论】:

  • 谢谢,但我不确定这是否是我要找的。 :) 我正在寻找一个会在每个滴答声上调用回调的代码。你有没有看过我的尝试,我的尝试完全错了,还是非常接近?

标签: c++ multithreading timer cross-platform ticker


【解决方案1】:

考虑以下带有用法示例的代码。我希望我正确地理解了你。 只需在单独的线程中运行 while 循环即可。

#include <cstdint>
#include <functional>
#include <chrono>
#include <thread>
#include <future>
#include <condition_variable>
#include <iostream>
#include <mutex>

class Ticker {
public:
    typedef std::chrono::duration<int64_t, std::nano> tick_interval_t;
    typedef std::function<void()> on_tick_t;

    Ticker (std::function<void()> onTick, std::chrono::duration<int64_t, std::nano> tickInterval) 
    : _onTick (onTick)
    , _tickInterval (tickInterval)
    , _running (false) {}
    ~Ticker () {}

    void start () {
        if (_running) return;
        _running = true;
        std::thread run(&Ticker::timer_loop, this);
        run.detach();
    }

    void stop () { _running = false; }

    void setDuration(std::chrono::duration<int64_t, std::nano> tickInterval)
    {
        _tickIntervalMutex.lock();
        _tickInterval = tickInterval;
        _tickIntervalMutex.unlock();
    }

private:
    void timer_loop()
    {
        while (_running) {
            std::thread run(_onTick );
            run.detach();

            _tickIntervalMutex.lock();
            std::chrono::duration<int64_t, std::nano> tickInterval = _tickInterval;
            _tickIntervalMutex.unlock();
            std::this_thread::sleep_for( tickInterval );
        }
    }

    on_tick_t           _onTick;
    tick_interval_t     _tickInterval;
    volatile bool       _running;
    std::mutex          _tickIntervalMutex;
};

void tick()
{
    std::cout << "tick\n";
}

void main()
{
    std::chrono::duration<int, std::milli> timer_duration1(1000);
    std::chrono::duration<int, std::milli> timer_duration2(500);
    std::chrono::duration<int> main_wait(5);

    Ticker ticker(std::function<void()>(tick), timer_duration1);
    ticker.start();

    std::this_thread::sleep_for(main_wait);
    ticker.setDuration(timer_duration2);
    std::this_thread::sleep_for(main_wait);
    ticker.stop();
}

【讨论】:

  • 赫瓦尔纳,非常感谢!这正是我一直在寻找的!如果可以,我对您的实现有疑问,特别是关于 std::mutex _tickIntervalMutex。如果我不使用任何锁来更新 _tickInterval,那么在最坏的情况下,我会调用 sleep_for() 并在循环中使用过期的 _tickInterval 值几次迭代?如果这是我会得到的唯一副作用,那么我会考虑删除这个互斥锁,因为我听说它们的 CPU 很重,在我的情况下,我可以忍受这种副作用......你觉得呢?
  • @mikeg 好吧,我不建议您将 _tickInterval 传递给函数 sleep_for,因为它是通过引用传递的,所以我不知道函数内部发生了什么,我可以t告诉你它会产生多么可怕的结果。此外,在没有互斥锁和解锁的情况下留下字符串... tickInterval = _tickInterval; 也不是一个好主意。想象一下,当 std::chrono::duration 的复制构造函数正在执行时,您正试图更改 _tickInterval。然后从旧值复制一半对象,从新值复制一半。不好。
  • @mikeg 我建议您以不同的方式实现它。将互斥锁和值复制移到 while 循环之外。在这种情况下,您将在一次启动时只调用一次互斥操作,但不是在每个计时器滴答时调用一次,这样就可以提高性能。但在这种情况下,您必须重新启动计时器以更改其间隔。请注意,_running 没有互斥体。只是因为没有办法像_tickInterval那样复制一半的值;它可以是真或假。
  • Hvarnah,我进步了,又遇到了一个与线程相关的问题。请看here好吗?
  • 这里需要可变对象吗?如果需要更改持续时间,取消并销毁第一个计时器似乎更合适,然后将其替换为不同配置的计时器。
猜你喜欢
  • 1970-01-01
  • 2012-12-02
  • 2018-01-22
  • 1970-01-01
  • 2020-09-04
  • 2018-11-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-03
相关资源
最近更新 更多