See*_*ker 3 c++ boost timer std qtimer
我必须每 5 秒执行一次任务,直到程序退出。我不想在这里使用线程。
在 QT 我可以这样做
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(1000);
Run Code Online (Sandbox Code Playgroud)
但是我如何使用 std 或 boost 库在 C++ 中做到这一点?
谢谢
我必须假设,“我不想使用线程”是指您不想在每次需要计时器时在自己的代码中创建线程。那是因为在没有线程的情况下做它实际上非常困难。
假设 C++11,你实际上可以只使用核心语言(不需要 Boost 或任何其他东西)并使用一个单独的类来处理线程,这样你在自己的代码中所需要的就是(例如,骚扰您的前合作伙伴处理垃圾邮件,这是一个相当可疑的用例):
Periodic spamEx(std::chrono::seconds(60), SendEmaiToEx);
Run Code Online (Sandbox Code Playgroud)
以下完整程序,编译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;
}
Run Code Online (Sandbox Code Playgroud)
当您创建 的实例时Periodic,它会保存相关信息并启动一个线程来完成工作。线程(一个 lambda)只是一个循环,它首先延迟一段时间然后调用你的函数。它会继续这样做,直到析构函数指示它应该停止。
正如预期的那样,输出是:
Starting main
Constructing periodic
Callback 1
Callback 2
Callback 3
Callback 4
Ending main
Destructed periodic
Run Code Online (Sandbox Code Playgroud)
(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();
}
}
});
Run Code Online (Sandbox Code Playgroud)
请注意,如果您的回调花费的时间超过该时间段,您基本上会几乎连续调用它(至少会有 100 毫秒的间隔)。
| 归档时间: |
|
| 查看次数: |
1558 次 |
| 最近记录: |