Stopping long-sleep threads
There are two traditional ways you could do this.
You could use a timed wait on a condition variable, and have the other thread signal your periodic thread to wake up and die when it's time.
Alternately you could poll
on a pipe with your sleep as a timeout instead of of sleeping. Then you just write a byte to the pipe and the thread wakes up and can exit.
Use a condition variable. You wait on the condition variable or 5 minutes passing. Remember to check for spurious wakeups.
cppreference
I cannot find a good stack overflow post on how to use a condition variable in a minute or two of google searching. The tricky part is realizing that the wait
can wake up with neither 5 minutes passing, nor a signal being sent. The cleanest way to handle this is to use the wait methods with a lambda that double-checks that the wakeup was a "good" one.
here is some sample code over at cppreference that uses wait_until
with a lambda. (wait_for
with a lambda is equivalent to wait_until
with a lambda). I modified it slightly.
Here is an version:
struct timer_killer {
// returns false if killed:
template<class R, class P>
bool wait_for( std::chrono::duration<R,P> const& time ) const {
std::unique_lock<std::mutex> lock(m);
return !cv.wait_for(lock, time, [&]{return terminate;});
}
void kill() {
std::unique_lock<std::mutex> lock(m);
terminate=true; // should be modified inside mutex lock
cv.notify_all(); // it is safe, and *sometimes* optimal, to do this outside the lock
}
// I like to explicitly delete/default special member functions:
timer_killer() = default;
timer_killer(timer_killer&&)=delete;
timer_killer(timer_killer const&)=delete;
timer_killer& operator=(timer_killer&&)=delete;
timer_killer& operator=(timer_killer const&)=delete;
private:
mutable std::condition_variable cv;
mutable std::mutex m;
bool terminate = false;
};
live example.
You create a timer_killer
in a shared spot. Client threads can wait_for( time )
. If it returns false, it means you where killed before your wait was complete.
The controlling thread just calls kill()
and everyone doing a wait_for
gets a false
return.
Note that there is some contention (locking of the mutex), so this isn't suitable for infinite threads (but few things are). Consider using a scheduler if you need to have an unbounded number of tasks that are run with arbitrary delays instead of a full thread per delayed repeating task -- each real thread is upwards of a megabyte of system address space used (just for the stack).