c++ - Threaded timer, interrupting a sleep (stopping it) -
i'm wanting reasonably reliable threaded timer, i've written timer object fires std::function on thread. give timer ability stop before gets next tick; can't ::sleep (at least don't think can).
so i've done put condition variable on mutex. if condition times out, fire event. if condition signalled thread exited. stop method needs able thread stop and/or interrupt wait, think it's doing right now.
there problems however. thread isn't joinable() , condition signalled after timeout before it's put wait state.
how can improve , make robust?
the following full repo. wait 10 seconds here program should terminate foo created , destroyed. not.
#include <atomic> #include <thread> #include <future> #include <sstream> #include <chrono> #include <iostream> class timer { public: timer() {} ~timer() { stop(); } void start(std::chrono::milliseconds const & interval, std::function<void(void)> const & callback) { stop(); thread = std::thread([=]() { for(;;) { auto locked = std::unique_lock<std::mutex>(mutex); auto result = terminate.wait_for(locked, interval); if (result == std::cv_status::timeout) { callback(); } else { return; } } }); } void stop() { terminate.notify_one(); if(thread.joinable()) { thread.join(); } } private: std::thread thread; std::mutex mutex; std::condition_variable terminate; }; class foo { public: foo() { timer = std::make_unique<timer>(); timer->start(std::chrono::milliseconds(10000), std::bind(&foo::callback, this)); } ~foo() { } void callback() { static int count = 0; std::ostringstream o; std::cout << count++ << std::endl; } std::unique_ptr<timer> timer; }; int main(void) { { foo foo; } return 0; }
see comment. forgot implement state of thing thread waiting for, leaving mutex nothing protect , thread nothing wait for. condition variables stateless -- code must track state of thing change you're notifying thread about.
here's code fixed. notice mutex protects stop
, , stop
thing thread waiting for.
class timer { public: timer() {} ~timer() { stop(); } void start(std::chrono::milliseconds const & interval, std::function<void(void)> const & callback) { stop(); { auto locked = std::unique_lock<std::mutex>(mutex); stop = false; } thread = std::thread([=]() { auto locked = std::unique_lock<std::mutex>(mutex); while (! stop) // hold mutex protects stop { auto result = terminate.wait_for(locked, interval); if (result == std::cv_status::timeout) { callback(); } } }); } void stop() { { // set predicate auto locked = std::unique_lock<std::mutex>(mutex); stop = true; } // tell thread predicate has changed terminate.notify_one(); if(thread.joinable()) { thread.join(); } } private: bool stop; // thing thread waiting std::thread thread; std::mutex mutex; std::condition_variable terminate; };
Comments
Post a Comment