One thing I noticed while searching for a simple, generic and pure C++ Timer class online, was the huge amount of answers that were floating around and none of them fit the exact description I was looking for. As a Qt Framework user I wanted to have something as close to QTimer as possible, or maybe even something like Timer class in .NET Framework and C# language. Well, I ended up writing one myself using what I could gather and this post is the summary of it all.
Following code snippet is the contents of timer.hpp file. Obviously, it can still be improved by adding a number of different constructors for convenience and even query methods, but the idea is to to have an interval in milliseconds, a task that is run at every interval and finally a simple flag to decide whether it should repeat or not.
#ifndef TIMER_H
#define TIMER_H
#include <chrono>
#include <functional>
#include <atomic>
#include <thread>
#include <condition_variable>
class Timer
{
public:
Timer(const std::chrono::milliseconds &interval,
const std::function<void ()> &task,
bool singleShot);
~Timer();
void Start();
void Stop();
void SetSingleShot(bool enabled = true);
bool IsRunning() const;
private:
std::chrono::milliseconds mInterval;
std::function<void ()> mTask;
std::atomic_bool mSingleShot;
std::atomic_bool mRunning;
std::condition_variable mRunCondition;
std::mutex mRunCondMutex;
std::thread mThread;
std::mutex mStopMutex;
};
#endif // TIMER_H
And the following is the contents of timer.cpp file. Notice how a std::condition_variable is used for a flexible wait, rather than just sleeping the thread unconditionally. Checking if the thread can be joined is another important thing to note. The rest should be self-explanatory but if you still have any questions you can use the comments section down below.
#include "timer.hpp"
Timer::Timer(const std::chrono::milliseconds &interval,
const std::function<void ()> &task,
bool singleShot)
: mInterval(interval),
mTask(task),
mSingleShot(singleShot),
mRunning(false)
{
}
Timer::~Timer()
{
Stop();
}
bool Timer::IsRunning() const
{
return mRunning;
}
void Timer::Start()
{
Stop();
mRunning = true;
mThread = std::thread([this]
{
while (mRunning)
{
std::unique_lock<std::mutex> lock(mRunCondMutex);
auto waitResult = mRunCondition.wait_for(lock, mInterval, [this]{ return !mRunning; });
if (mRunning && !waitResult)
mTask();
if(mSingleShot)
mRunning = false;
}
});
}
void Timer::SetSingleShot(bool enabled)
{
mSingleShot = enabled;
}
void Timer::Stop()
{
std::unique_lock<std::mutex> lock(mStopMutex);
mRunning = false;
mRunCondition.notify_all();
if(mThread.joinable())
mThread.join();
}
Finally, here is an example code that demonstrates how this class is actually used, which is quite similar to how QTimer class and other similar generic Timer classes are used:
auto task = []()
{
// Do something
};
mTimer = std::make_shared<Timer>(std::chrono::seconds(1), task, true);
mTimer->Start();
How would you compile this using GCC (6.3) under Windows (7-64)?
The problem is ‘thread’ and ‘mutex’ “not naming a type”.
See if this helps:
https://gcc.gnu.org/projects/cxx-status.html#cxx11