Lumiera  0.pre.03
»edit your freedom«
sync.hpp
Go to the documentation of this file.
1 /*
2  SYNC.hpp - generic helper for object based locking and synchronisation
3 
4  Copyright (C)
5  2007, Christian Thaeter <ct@pipapo.org>
6  2008, Hermann Vosseler <Ichthyostega@web.de>
7  2023, Hermann Vosseler <Ichthyostega@web.de>
8 
9   **Lumiera** is free software; you can redistribute it and/or modify it
10   under the terms of the GNU General Public License as published by the
11   Free Software Foundation; either version 2 of the License, or (at your
12   option) any later version. See the file COPYING for further details.
13 
14 */
15 
63 #ifndef LIB_SYNC_H
64 #define LIB_SYNC_H
65 
66 #include "lib/error.hpp"
67 #include "lib/nocopy.hpp"
68 #include "lib/util.hpp"
69 
70 #include <mutex>
71 #include <condition_variable>
72 #include <chrono>
73 
74 
75 namespace lib {
76 
78  namespace sync {
79 
80  /* ========== policies to define required degree of locking functionality ============== */
81 
82  template<class MTX>
83  struct Condition
84  : MTX
85  , std::condition_variable_any
86  {
87 
88  template<class PRED>
89  void
90  wait (PRED&& predicate)
91  {
92  condVar().wait (mutex(), std::forward<PRED> (predicate));
93  }
94 
98  template<class REPR, class PERI, class PRED>
99  bool
100  wait_for (std::chrono::duration<REPR, PERI> const& timeout, PRED&& predicate)
101  {
102  return condVar().wait_for (mutex(), timeout, std::forward<PRED> (predicate));
103  }
104 
105  MTX&
106  mutex()
107  {
108  return static_cast<MTX&> (*this);
109  }
110  std::condition_variable_any&
111  condVar()
112  {
113  return static_cast<std::condition_variable_any&> (*this);
114  }
115  };
116 
117  struct NoLocking
118  {
119  void lock() { /* boo */ }
120  void unlock() noexcept { /* hoo */ }
121  };
122 
123 
124 
125  /* ========== Object Monitor ============== */
126 
132  template<class IMPL>
133  class Monitor
134  : IMPL
136  {
137  public:
138 
139  void lock() { IMPL::lock(); }
140  void unlock() noexcept { IMPL::unlock(); }
141 
142  void notify_one() noexcept { IMPL::notify_one(); }
143  void notify_all() noexcept { IMPL::notify_all(); }
144 
145  template<class PRED>
146  void
147  wait (PRED&& predicate)
148  {
149  IMPL::wait (std::forward<PRED>(predicate));
150  }
151 
152  template<class DUR, class PRED>
153  bool
154  wait_for (DUR const& timeout, PRED&& predicate)
155  {
156  return IMPL::wait_for (timeout, std::forward<PRED> (predicate));
157  }
158  };
159 
160  using NonrecursiveLock_NoWait = std::mutex;
161  using RecursiveLock_NoWait = std::recursive_mutex;
164 
165 
166  } // namespace sync (helpers and building blocks)
167 
168 
169 
170 
171 
172  /* Interface to be used by client code:
173  * Inherit from class Sync with a suitable Policy.
174  * Then use the embedded Lock class.
175  */
176 
177  /* ======= Policy classes ======= */
178 
179  using sync::NonrecursiveLock_NoWait;
181  using sync::RecursiveLock_NoWait;
183 
184 
185  /*********************************************************************/
208  template<class CONF = NonrecursiveLock_NoWait>
209  class Sync
210  {
212  mutable Monitor objectMonitor_;
213 
214  public:
215  static Monitor&
216  getMonitor(Sync const* forThis)
217  {
218  REQUIRE (forThis);
219  return forThis->objectMonitor_;
220  }
221 
222 
223  /*****************************************/
226  class Lock
228  {
229  Monitor& mon_;
230 
231  public:
232  template<class X>
233  Lock(X* it) : mon_{getMonitor(it)}{ mon_.lock(); }
234  ~Lock() { mon_.unlock(); }
235 
236  void notify_one() { mon_.notify_one(); }
237  void notify_all() { mon_.notify_all(); }
238 
239  template<class PRED>
240  void
241  wait (PRED&& predicate)
242  {
243  mon_.wait (std::forward<PRED>(predicate));
244  }
245 
246  template<class DUR, class PRED>
247  bool
248  wait_for (DUR const& timeout, PRED&& predicate)
249  {
250  return mon_.wait_for (timeout, std::forward<PRED> (predicate));
251  }
252 
256  template<class X, class PRED>
257  Lock(X* it, PRED&& predicate)
258  : mon_(getMonitor(it))
259  {
260  mon_.lock();
261  try {
262  mon_.wait (std::forward<PRED>(predicate));
263  }
264  catch(...)
265  {
266  mon_.unlock();
267  throw;
268  }
269  }
270 
271  protected:
274  : mon_{m}
275  {
276  mon_.lock();
277  }
278 
280  Monitor& accessMonitor() { return mon_; }
281  };
282  };
283 
284 
285 } // namespace lumiera
286 #endif
Facility for monitor object based locking.
Definition: sync.hpp:209
Lock(Monitor &m)
for creating a ClassLock
Definition: sync.hpp:273
Any copy and copy construction prohibited.
Definition: nocopy.hpp:37
scoped guard to control the actual locking.
Definition: sync.hpp:226
Implementation namespace for support and library code.
Mix-Ins to allow or prohibit various degrees of copying and cloning.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
bool wait_for(std::chrono::duration< REPR, PERI > const &timeout, PRED &&predicate)
Definition: sync.hpp:100
Lock(X *it, PRED &&predicate)
convenience shortcut: Locks and immediately enters wait state on the given predicate ...
Definition: sync.hpp:257
Lumiera error handling (C++ interface).
Monitor & accessMonitor()
subclass access to underlying sync primitives
Definition: sync.hpp:280
Object Monitor for synchronisation and waiting.
Definition: sync.hpp:133