Also irgendwie ist das schon eine recht komische Timer Implementierung. Es wird eine Klasse verwendet, aber kein RAII und deswegen wohl auch das thread.detach(). Entkoppelte Threads sind in der Regel immer "böse", sollte man einfach nicht machen. Falls du C++17 verwenden kannst, kann man daraus ein recht brauchbares Template machen. So spontan hätte ich mir den Timer so gebastelt, wenn ich keine großen Anforderungen habe.
#include <chrono>
#include <functional>
#include <iostream>
#include <thread>
template <bool Async = true, bool Joinable = true>
struct Timer {
template <typename Callable, typename... Args>
Timer(const size_t wait_ms, Callable &&func, Args &&...args)
{
auto task(std::bind(std::forward<Callable>(func), std::forward<Args>(args)...));
if constexpr (Async)
{
_thread = std::thread([wait_ms, task]()
{
std::this_thread::sleep_for(std::chrono::milliseconds(wait_ms));
task();
});
if constexpr (!Joinable)
_thread.detach();
}
else
{
std::this_thread::sleep_for(std::chrono::milliseconds(wait_ms));
task();
}
}
~Timer()
{
if (Joinable && _thread.joinable())
_thread.join();
}
std::thread _thread;
};
Und dieses Timer Template kann man dann so benutzen:
void test(const char *arg)
{
std::cout << arg << std::endl;
}
int32_t main()
{
Timer timer1(2000, test, "timer1");
Timer timer2(1000, test, "timer2");
return 0;
}
Dieses einfache Template unterstützt keine Rückgabewerte. Man kann aber das Template nehmen und statt alles im Constructor zu machen, schiebt man einfach alles zum Beispiel in den function call operator (operator()). Dann muss man sich noch aus einem Promise/Future einen Rückgabewert-Container basteln und tataaa, man kann sich auch Rückgabewerte geben lassen. Wenn man es noch etwas bunter will, kann man auch mit condition variables das Ganze abbrechbar machen (sleep_for durch condition_variable::wait_for Konstruktion ersetzen).