提问人:Dominic Sesto 提问时间:5/19/2023 最后编辑:Dominic Sesto 更新时间:5/19/2023 访问量:435
具有启动/停止函数的 C++ 回调计时器
C++ callback timer with start/stop functions
问:
我需要创建一个类来复制我不再有权访问的库中的回调计时器的功能。
基本上,生成一个异步线程,该线程在达到超时后执行某些函数。但是,如果在超时之前满足某些条件,则不会执行该函数,并且计时器将被取消。
我不确定如何根据某些条件“停止”计时器。
这就是我到目前为止所拥有的(基于这篇文章的答案 C++ 非阻塞异步计时器 by wally)
#include <iostream>
#include <chrono>
#include <thread>
#include <functional>
#include <mutex>
#include <condition_variable>
class Timer
{
public:
Timer(size_t time, const std::function<void(void)>& callback) :
time(std::chrono::milliseconds(time)),
callback(callback) {}
~Timer()
{
if (started)
{
wait_thread.join();
started = false;
}
}
// TODO: Implement stop()
void stop()
{
// ???
}
// TODO: Implement start()
void start()
{
if (!started)
{
started = true;
wait_thread = std::thread{ [this]() { wait_then_call(); } };
}
else
{
std::cout << "Thread " << wait_thread.get_id() << " already been started! " << std::endl;
}
}
private:
void wait_then_call()
{
std::unique_lock<std::mutex> lck(mtx);
std::cout << "Thread " << wait_thread.get_id() << " starting in " << time/1000 << " seconds" << std::endl;
cv.wait_for(lck, time);
callback();
}
std::mutex mtx;
std::condition_variable cv{};
std::chrono::milliseconds time;
std::function <void(void)> callback;
std::thread wait_thread;
bool started = false;
};
测试:
int main()
{
auto f = []() {std::cout << "Executing Callback Function"; };
Timer t1{ 3000, f };
t1.start();
Timer t2{ 10000, f };
t2.start();
// main thread is free to continue doing other things
}
答:
0赞
RandomBits
5/19/2023
#1
我认为以下内容符合您的所有要求。
示例代码
#include <condition_variable>
#include <chrono>
#include <iostream>
#include <thread>
template<class F>
class DelayedExecution {
public:
DelayedExecution(std::chrono::milliseconds ms, F&& func)
: ms_(ms)
, func_(std::forward<F>(func)) {
}
~DelayedExecution() {
if (thread_.joinable())
thread_.join();
}
void start() {
thread_ = std::thread{ [this]() {
std::unique_lock<std::mutex> lck(mutex_);
cv_.wait_for(lck, ms_, [this]() { return stop_waiting_.load(); });
if (not stop_waiting_)
func_();
}};
}
void stop() {
stop_waiting_.store(true);
cv_.notify_one();
}
private:
std::chrono::milliseconds ms_;
F func_;
std::thread thread_;
std::condition_variable cv_;
std::mutex mutex_;
std::atomic<bool> stop_waiting_{false};
};
using std::cout, std::endl;
int main(int argc, const char *argv[]) {
DelayedExecution task1(std::chrono::milliseconds{250}, []() { cout << "task1" << endl; });
DelayedExecution task2(std::chrono::milliseconds{250}, []() { cout << "task2" << endl; });
task1.start();
task2.start();
task1.stop();
return 0;
}
输出
task2
评论
0赞
Dominic Sesto
5/19/2023
如果我需要多次启动/停止定时器怎么办?
0赞
user4581301
5/19/2023
这是一个纯代码答案。幸运的是,通过加入合理的解释量(在这种情况下很少)可以很容易地解决这个问题。
0赞
user4581301
5/19/2023
@DominicSesto 将 stop_waiting_' 设置为开头,您应该能够随心所欲地重复使用......只要您确保正在运行的线程有时间确认条件变量并退出即可。如果没有更多的基础设施,这可能很难保证。false
start
0赞
RandomBits
5/19/2023
@DominicSesto 当您多次说启动和停止计时器时,计时器应该在每次停止时重置,还是希望它以相同的倒计时继续?重置是一个很小的更改,但能够打开和关闭倒计时需要重新考虑,因为当前解决方案中没有任何内容跟踪用完的时间。
0赞
RandomBits
5/19/2023
@DominicSesto 此外,允许计时器在停止后重新启动会引入同步问题。由于是非阻塞的,它将立即返回,客户端线程无法知道何时可以安全地重新启动计时器。而且,如果在设置标志之前调用函数并调用该函数怎么办? 需要返回函数是否被调用的指示。而且,如果您重新启动计时器,是否应该再次调用它?这需要更详细地说明它应该如何表现。stop
stop
stop
stop
评论
wait_for
wait_for
wait_for()
stop
wait_then_call