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) Lumiera.org
5  2008, Christian Thaeter <ct@pipapo.org>
6  Hermann Vosseler <Ichthyostega@web.de>
7 
8  This program is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2 of
11  the License, or (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 
22 */
23 
71 #ifndef LIB_SYNC_H
72 #define LIB_SYNC_H
73 
74 #include "lib/error.hpp"
75 #include "lib/nocopy.hpp"
76 #include "lib/util.hpp"
77 
78 #include <mutex>
79 #include <condition_variable>
80 #include <chrono>
81 
82 
83 namespace lib {
84 
86  namespace sync {
87 
88  /* ========== policies to define required degree of locking functionality ============== */
89 
90  template<class MTX>
91  struct Condition
92  : MTX
93  , std::condition_variable_any
94  {
95 
96  template<class PRED>
97  void
98  wait (PRED&& predicate)
99  {
100  condVar().wait (mutex(), std::forward<PRED> (predicate));
101  }
102 
106  template<class REPR, class PERI, class PRED>
107  bool
108  wait_for (std::chrono::duration<REPR, PERI> const& timeout, PRED&& predicate)
109  {
110  return condVar().wait_for (mutex(), timeout, std::forward<PRED> (predicate));
111  }
112 
113  MTX&
114  mutex()
115  {
116  return static_cast<MTX&> (*this);
117  }
118  std::condition_variable_any&
119  condVar()
120  {
121  return static_cast<std::condition_variable_any&> (*this);
122  }
123  };
124 
125  struct NoLocking
126  {
127  void lock() { /* boo */ }
128  void unlock() noexcept { /* hoo */ }
129  };
130 
131 
132 
133  /* ========== Object Monitor ============== */
134 
140  template<class IMPL>
141  class Monitor
142  : IMPL
144  {
145  public:
146 
147  void lock() { IMPL::lock(); }
148  void unlock() noexcept { IMPL::unlock(); }
149 
150  void notify_one() noexcept { IMPL::notify_one(); }
151  void notify_all() noexcept { IMPL::notify_all(); }
152 
153  template<class PRED>
154  void
155  wait (PRED&& predicate)
156  {
157  IMPL::wait (std::forward<PRED>(predicate));
158  }
159 
160  template<class DUR, class PRED>
161  bool
162  wait_for (DUR const& timeout, PRED&& predicate)
163  {
164  return IMPL::wait_for (timeout, std::forward<PRED> (predicate));
165  }
166  };
167 
168  using NonrecursiveLock_NoWait = std::mutex;
169  using RecursiveLock_NoWait = std::recursive_mutex;
172 
173 
174  } // namespace sync (helpers and building blocks)
175 
176 
177 
178 
179 
180  /* Interface to be used by client code:
181  * Inherit from class Sync with a suitable Policy.
182  * Then use the embedded Lock class.
183  */
184 
185  /* ======= Policy classes ======= */
186 
187  using sync::NonrecursiveLock_NoWait;
189  using sync::RecursiveLock_NoWait;
191 
192 
193  /*********************************************************************/
216  template<class CONF = NonrecursiveLock_NoWait>
217  class Sync
218  {
220  mutable Monitor objectMonitor_;
221 
222  public:
223  static Monitor&
224  getMonitor(Sync const* forThis)
225  {
226  REQUIRE (forThis);
227  return forThis->objectMonitor_;
228  }
229 
230 
231  /*****************************************/
234  class Lock
236  {
237  Monitor& mon_;
238 
239  public:
240  template<class X>
241  Lock(X* it) : mon_{getMonitor(it)}{ mon_.lock(); }
242  ~Lock() { mon_.unlock(); }
243 
244  void notify_one() { mon_.notify_one(); }
245  void notify_all() { mon_.notify_all(); }
246 
247  template<class PRED>
248  void
249  wait (PRED&& predicate)
250  {
251  mon_.wait (std::forward<PRED>(predicate));
252  }
253 
254  template<class DUR, class PRED>
255  bool
256  wait_for (DUR const& timeout, PRED&& predicate)
257  {
258  return mon_.wait_for (timeout, std::forward<PRED> (predicate));
259  }
260 
264  template<class X, class PRED>
265  Lock(X* it, PRED&& predicate)
266  : mon_(getMonitor(it))
267  {
268  mon_.lock();
269  try {
270  mon_.wait (std::forward<PRED>(predicate));
271  }
272  catch(...)
273  {
274  mon_.unlock();
275  throw;
276  }
277  }
278 
279  protected:
282  : mon_{m}
283  {
284  mon_.lock();
285  }
286 
288  Monitor& accessMonitor() { return mon_; }
289  };
290  };
291 
292 
293 } // namespace lumiera
294 #endif
Facility for monitor object based locking.
Definition: sync.hpp:217
Lock(Monitor &m)
for creating a ClassLock
Definition: sync.hpp:281
Any copy and copy construction prohibited.
Definition: nocopy.hpp:46
scoped guard to control the actual locking.
Definition: sync.hpp:234
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:108
Lock(X *it, PRED &&predicate)
convenience shortcut: Locks and immediately enters wait state on the given predicate ...
Definition: sync.hpp:265
Lumiera error handling (C++ interface).
Monitor & accessMonitor()
subclass access to underlying sync primitives
Definition: sync.hpp:288
Object Monitor for synchronisation and waiting.
Definition: sync.hpp:141