]> git.sesse.net Git - nageru/blob - quittable_sleeper.h
Fix an issue where the mixer lagging too much behind CEF would cause us to display...
[nageru] / quittable_sleeper.h
1 #ifndef _QUITTABLE_SLEEPER
2 #define _QUITTABLE_SLEEPER 1
3
4 // A class that assists with fast shutdown of threads. You can set
5 // a flag that says the thread should quit, which it can then check
6 // in a loop -- and if the thread sleeps (using the sleep_* functions
7 // on the class), that sleep will immediately be aborted.
8 //
9 // All member functions on this class are thread-safe.
10
11 #include <chrono>
12 #include <mutex>
13
14 class QuittableSleeper {
15 public:
16         void quit()
17         {
18                 std::lock_guard<std::mutex> l(mu);
19                 should_quit_var = true;
20                 quit_cond.notify_all();
21         }
22
23         void unquit()
24         {
25                 std::lock_guard<std::mutex> l(mu);
26                 should_quit_var = false;
27         }
28
29         void wakeup()
30         {
31                 std::lock_guard<std::mutex> l(mu);
32                 should_wakeup_var = true;
33                 quit_cond.notify_all();
34         }
35
36         bool should_quit() const
37         {
38                 std::lock_guard<std::mutex> l(mu);
39                 return should_quit_var;
40         }
41
42         // Returns false if woken up early.
43         template<class Rep, class Period>
44         bool sleep_for(const std::chrono::duration<Rep, Period> &duration)
45         {
46                 std::chrono::steady_clock::time_point t =
47                         std::chrono::steady_clock::now() +
48                         std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration);
49                 return sleep_until(t);
50         }
51
52         // Returns false if woken up early.
53         template<class Clock, class Duration>
54         bool sleep_until(const std::chrono::time_point<Clock, Duration> &t)
55         {
56                 std::unique_lock<std::mutex> lock(mu);
57                 quit_cond.wait_until(lock, t, [this]{
58                         return should_quit_var || should_wakeup_var;
59                 });
60                 if (should_wakeup_var) {
61                         should_wakeup_var = false;
62                         return false;
63                 }
64                 return !should_quit_var;
65         }
66
67 private:
68         mutable std::mutex mu;
69         bool should_quit_var = false, should_wakeup_var = false;
70         std::condition_variable quit_cond;
71 };
72
73 #endif  // !defined(_QUITTABLE_SLEEPER)