WPILibC++  unspecified
SafeThread.h
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) FIRST 2015. 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 #ifndef WPIUTIL_SUPPORT_SAFETHREAD_H_
9 #define WPIUTIL_SUPPORT_SAFETHREAD_H_
10 
11 #include <atomic>
12 #include <condition_variable>
13 #include <mutex>
14 #include <thread>
15 
16 namespace wpi {
17 
18 // Base class for SafeThreadOwner threads.
19 class SafeThread {
20  public:
21  SafeThread() { m_active = true; }
22  virtual ~SafeThread() = default;
23  virtual void Main() = 0;
24 
25  std::mutex m_mutex;
26  std::atomic_bool m_active;
27  std::condition_variable m_cond;
28 };
29 
30 namespace detail {
31 
32 // Non-template proxy base class for common proxy code.
34  public:
35  SafeThreadProxyBase(SafeThread* thr) : m_thread(thr) {
36  if (!m_thread) return;
37  std::unique_lock<std::mutex>(m_thread->m_mutex).swap(m_lock);
38  if (!m_thread->m_active) {
39  m_lock.unlock();
40  m_thread = nullptr;
41  return;
42  }
43  }
44  explicit operator bool() const { return m_thread != nullptr; }
45  std::unique_lock<std::mutex>& GetLock() { return m_lock; }
46 
47  protected:
48  SafeThread* m_thread;
49  std::unique_lock<std::mutex> m_lock;
50 };
51 
52 // A proxy for SafeThread.
53 // Also serves as a scoped lock on SafeThread::m_mutex.
54 template <typename T>
56  public:
58  T& operator*() const { return *static_cast<T*>(m_thread); }
59  T* operator->() const { return static_cast<T*>(m_thread); }
60 };
61 
62 // Non-template owner base class for common owner code.
64  public:
65  void Stop();
66 
67  SafeThreadOwnerBase() { m_thread = nullptr; }
69  SafeThreadOwnerBase& operator=(const SafeThreadOwnerBase&) = delete;
71  : m_thread(other.m_thread.exchange(nullptr)) {}
72  SafeThreadOwnerBase& operator=(SafeThreadOwnerBase other) {
73  SafeThread* otherthr = other.m_thread.exchange(nullptr);
74  SafeThread* curthr = m_thread.exchange(otherthr);
75  other.m_thread.exchange(curthr); // other destructor will clean up
76  return *this;
77  }
78  ~SafeThreadOwnerBase() { Stop(); }
79 
80  explicit operator bool() const { return m_thread.load(); }
81 
82  protected:
83  void Start(SafeThread* thr);
84  SafeThread* GetThread() const { return m_thread.load(); }
85  std::thread::native_handle_type GetNativeThreadHandle() const {
86  return m_nativeHandle;
87  }
88 
89  private:
90  std::atomic<SafeThread*> m_thread;
91  std::atomic<std::thread::native_handle_type> m_nativeHandle;
92 };
93 
94 inline void SafeThreadOwnerBase::Start(SafeThread* thr) {
95  SafeThread* curthr = nullptr;
96  SafeThread* newthr = thr;
97  if (!m_thread.compare_exchange_strong(curthr, newthr)) {
98  delete newthr;
99  return;
100  }
101  std::thread stdThread([=]() {
102  newthr->Main();
103  delete newthr;
104  });
105  m_nativeHandle = stdThread.native_handle();
106  stdThread.detach();
107 }
108 
109 inline void SafeThreadOwnerBase::Stop() {
110  SafeThread* thr = m_thread.exchange(nullptr);
111  if (!thr) return;
112  thr->m_active = false;
113  thr->m_cond.notify_one();
114 }
115 
116 } // namespace detail
117 
118 template <typename T>
120  public:
121  void Start() { Start(new T); }
122  void Start(T* thr) { detail::SafeThreadOwnerBase::Start(thr); }
123 
124  using Proxy = typename detail::SafeThreadProxy<T>;
125  Proxy GetThread() const {
126  return Proxy(detail::SafeThreadOwnerBase::GetThread());
127  }
128 };
129 
130 } // namespace wpi
131 
132 #endif // WPIUTIL_SUPPORT_SAFETHREAD_H_
Definition: SafeThread.h:55
Definition: SafeThread.h:19
Definition: SafeThread.h:119
Definition: SocketError.cpp:18
Definition: SafeThread.h:63
Definition: SafeThread.h:33