WPILibC++  unspecified
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Pages
priority_condition_variable.h
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
3 /* Open Source Software - may be modified and shared by FRC teams. The code */
4 /* must be accompanied by the FIRST BSD license file in the root directory of */
5 /* the project. */
6 /*----------------------------------------------------------------------------*/
7 
8 #pragma once
9 
10 /* std::condition_variable provides the native_handle() method to return its
11  * underlying pthread_cond_t*. WPILib uses this to interface with the FRC
12  * network communication library. Since WPILib uses a custom mutex class and
13  * not std::mutex, std::condition_variable_any must be used instead.
14  * std::condition_variable_any doesn't expose its internal handle, so this
15  * class provides the same interface and implementation in addition to a
16  * native_handle() method.
17  */
18 
19 #include <condition_variable>
20 #include <memory>
21 #include <utility>
22 
23 #include "priority_mutex.h"
24 
26  typedef std::chrono::system_clock clock;
27 
28  public:
29  typedef std::condition_variable::native_handle_type native_handle_type;
30 
31  priority_condition_variable() : m_mutex(std::make_shared<std::mutex>()) {}
32  ~priority_condition_variable() = default;
33 
36  delete;
37 
38  void notify_one() noexcept {
39  std::lock_guard<std::mutex> lock(*m_mutex);
40  m_cond.notify_one();
41  }
42 
43  void notify_all() noexcept {
44  std::lock_guard<std::mutex> lock(*m_mutex);
45  m_cond.notify_all();
46  }
47 
48  template <typename Lock>
49  void wait(Lock& _lock) {
50  std::shared_ptr<std::mutex> _mutex = m_mutex;
51  std::unique_lock<std::mutex> my_lock(*_mutex);
52  Unlock<Lock> unlock(_lock);
53 
54  // *mutex must be unlocked before re-locking _lock so move
55  // ownership of *_mutex lock to an object with shorter lifetime.
56  std::unique_lock<std::mutex> my_lock2(std::move(my_lock));
57  m_cond.wait(my_lock2);
58  }
59 
60  template <typename Lock, typename Predicate>
61  void wait(Lock& lock, Predicate p) {
62  while (!p()) {
63  wait(lock);
64  }
65  }
66 
67  template <typename Lock, typename Clock, typename Duration>
68  std::cv_status wait_until(
69  Lock& _lock, const std::chrono::time_point<Clock, Duration>& atime) {
70  std::shared_ptr<std::mutex> _mutex = m_mutex;
71  std::unique_lock<std::mutex> my_lock(*_mutex);
72  Unlock<Lock> unlock(_lock);
73 
74  // *_mutex must be unlocked before re-locking _lock so move
75  // ownership of *_mutex lock to an object with shorter lifetime.
76  std::unique_lock<std::mutex> my_lock2(std::move(my_lock));
77  return m_cond.wait_until(my_lock2, atime);
78  }
79 
80  template <typename Lock, typename Clock, typename Duration,
81  typename Predicate>
82  bool wait_until(Lock& lock,
83  const std::chrono::time_point<Clock, Duration>& atime,
84  Predicate p) {
85  while (!p()) {
86  if (wait_until(lock, atime) == std::cv_status::timeout) {
87  return p();
88  }
89  }
90  return true;
91  }
92 
93  template <typename Lock, typename Rep, typename Period>
94  std::cv_status wait_for(Lock& lock,
95  const std::chrono::duration<Rep, Period>& rtime) {
96  return wait_until(lock, clock::now() + rtime);
97  }
98 
99  template <typename Lock, typename Rep, typename Period, typename Predicate>
100  bool wait_for(Lock& lock, const std::chrono::duration<Rep, Period>& rtime,
101  Predicate p) {
102  return wait_until(lock, clock::now() + rtime, std::move(p));
103  }
104 
105  native_handle_type native_handle() { return m_cond.native_handle(); }
106 
107  private:
108  std::condition_variable m_cond;
109  std::shared_ptr<std::mutex> m_mutex;
110 
111  // scoped unlock - unlocks in ctor, re-locks in dtor
112  template <typename Lock>
113  struct Unlock {
114  explicit Unlock(Lock& lk) : m_lock(lk) { lk.unlock(); }
115 
116  ~Unlock() /*noexcept(false)*/ {
117  if (std::uncaught_exception()) {
118  try {
119  m_lock.lock();
120  } catch (...) {
121  }
122  } else {
123  m_lock.lock();
124  }
125  }
126 
127  Unlock(const Unlock&) = delete;
128  Unlock& operator=(const Unlock&) = delete;
129 
130  Lock& m_lock;
131  };
132 };
Definition: priority_condition_variable.h:25