在C++中使用std或boost库的Qtimer等价物是什么

What is the equivalent of Qtimer in C++ using std or boost libraries?

本文关键字:库的 boost Qtimer 等价物 是什么 std C++      更新时间:2023-10-16

我必须每5秒执行一次任务,直到程序退出。我不想在这里使用线程。

在QT中,我可以像这个一样

QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(1000);

但是我如何在c++中使用std或boost库来实现这一点呢?

谢谢

我不得不假设,"我不想使用线程"的意思是,你不想每次需要计时器时都在自己的代码中创建线程。这是因为在没有线程的情况下执行它实际上相当困难。

假设C++11,你实际上可以用来实现这一点,只需核心语言(不需要Boost或任何其他东西(,并使用一个单独的类来处理线程,这样你在自己的代码中所需要的就是类似的东西(例如,用垃圾邮件骚扰你的前伴侣,这是一个相当可疑的用例(:

Periodic spamEx(std::chrono::seconds(60), SendEmaiToEx);

以下用g++ -std=c++11 -o periodic periodic.cpp -lpthread编译的完整程序将每秒运行一个周期性回调函数,持续五秒(a(

#include <thread>
#include <chrono>
#include <functional>
#include <atomic>
// Not needed if you take couts out of Periodic class.
#include <iostream>
class Periodic {
public:
explicit Periodic(
const std::chrono::milliseconds &period,
const std::function<void ()> &func
)
: m_period(period)
, m_func(func)
, m_inFlight(true)
{
std::cout << "Constructing periodic" << std::endl;
m_thread = std::thread([this] {
while (m_inFlight) {
std::this_thread::sleep_for(m_period);
if (m _inFlight) {
m_func();
}
}
});
}
~Periodic() {
std::cout << "Destructed periodic" << std::endl;
m_inFlight = false;
m_thread.join();
std::cout << "Destructed periodic" << std::endl;
}
private:
std::chrono::milliseconds m_period;
std::function<void ()> m_func;
std::atomic<bool> m_inFlight;
std::thread m_thread;
};
// This is a test driver, the "meat" is above this.
#include <iostream>
void callback() {
static int counter = 0;
std::cout << "Callback " << ++counter << std::endl;
}
int main() {
std::cout << "Starting main" << std::endl;
Periodic p(std::chrono::seconds(1), callback);
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "Ending main" << std::endl;
}

当您创建Periodic的实例时,它会保存相关信息并启动一个线程来完成工作。线程(lambda(只是一个循环,它首先延迟一段时间,然后调用您的函数。它继续这样做,直到析构函数指示它应该停止为止。

输出如预期:

Starting main
Constructing periodic
Callback 1
Callback 2
Callback 3
Callback 4
Ending main
Destructed periodic

(a(注意,上面给出的时间实际上是从一个回调结束到下一个回调开始的时间,而不是从开始到开始的时间(我称之为真正的循环时间(。如果你的回调与同期相比足够快,那么差异有望不会明显。

此外,线程无论如何都会延迟,因此析构函数在返回之前可能会延迟一整段时间。

如果确实需要一个从开始到开始的时间段和快速清理,则可以使用以下线程。它确实通过计算回调的持续时间开始计时,并且只延迟时段的剩余(或者如果回调使用了整个时段,则根本不延迟(。

它还使用较小的睡眠时间,因此清理速度很快。线程函数为:

m_thread = std::thread([this] {
// Ensure we wait the initial period, then start loop.
auto lastCallback = std::chrono::steady_clock::now();
while (m_inFlight) {
// Small delay, then get current time.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
auto timeNow = std::chrono::steady_clock::now();
// Only callback if still active and current period has expired.
if (m_inFlight && timeNow - lastCallback >= m_period) {
// Start new period and call callback.
lastCallback = timeNow;
m_func();
}
}
});

请注意,如果你的回调时间比这段时间长,你基本上会连续调用它(至少会有100毫秒的间隔(。

您意识到QTimer确实使用了线程,或者在主事件循环中轮询计时器。你也可以这么做。您可能遇到的概念问题是,您没有UI,因此可能没有创建事件循环。

以下是利用Boost Asio进行事件循环的最简单方法:

在Coliru上直播

#include <boost/asio.hpp>
#include <boost/asio/high_resolution_timer.hpp>
#include <functional>
#include <chrono>
#include <iostream>
using namespace std::chrono_literals;
using boost::system::error_code;
namespace ba = boost::asio;
int main() {
ba::io_service svc; // prefer io_context in recent boost versions
ba::high_resolution_timer timer{svc};
std::function<void()> resume;
resume = [&] {
timer.expires_from_now(50ms); // just for demo, don't wait 5s but 50ms
timer.async_wait([=,&timer](error_code ec) {
std::cout << "Timer: " << ec.message() << "n";
if (!ec) 
resume();
});
};
resume();
svc.run_for(200ms); // probably getting 3 or 4 successful callbacks
timer.cancel();
svc.run(); // graceful shutdown
}

打印:

Timer: Success
Timer: Success
Timer: Success
Timer: Success
Timer: Operation canceled

根据应用程序的其余部分,这可能没有太大意义。在这种情况下,您可以执行相同的操作,但使用单独的线程(yes(来运行该事件循环。