Lunchbox  1.12.0
Multi-threaded C++ toolbox library for all application developers creating high-performance multi-threaded programs.
monitor.h
1 /* Copyright (c) 2006-2013, Stefan Eilemann <eile@equalizergraphics.com>
2  * 2011, Cedric Stalder <cedric.stalder@gmail.com>
3  * 2011-2012, Daniel Nachbaur <danielnachbaur@gmail.com>
4  *
5  * This library is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU Lesser General Public License version 2.1 as published
7  * by the Free Software Foundation.
8  *
9  * This library is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12  * details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 #ifndef LUNCHBOX_MONITOR_H
20 #define LUNCHBOX_MONITOR_H
21 
22 #include <lunchbox/condition.h> // member
23 #include <lunchbox/scopedMutex.h> // used inline
24 #include <lunchbox/types.h>
25 
26 #include <errno.h>
27 #include <string.h>
28 #include <iostream>
29 #include <typeinfo>
30 #include <functional>
31 #include <boost/bind.hpp>
32 
33 namespace lunchbox
34 {
44 template< class T > class Monitor
45 {
46  typedef void (Monitor< T >::*bool_t)() const;
47  void bool_true() const {}
48 
49 public:
51  Monitor() : _value( T( 0 )) {}
52 
54  explicit Monitor( const T& value ) : _value( value ) {}
55 
57  Monitor( const Monitor< T >& from ) : _value( from._value ) {}
58 
60  ~Monitor() {}
61 
66  {
67  ScopedCondition mutex( _cond );
68  ++_value;
69  _cond.broadcast();
70  return *this;
71  }
72 
75  {
76  ScopedCondition mutex( _cond );
77  --_value;
78  _cond.broadcast();
79  return *this;
80  }
81 
83  Monitor& operator = ( const T& value )
84  { set( value ); return *this; }
85 
87  const Monitor& operator = ( const Monitor< T >& from )
88  { set( from._value ); return *this; }
89 
91  Monitor& operator |= ( const T& value )
92  {
93  ScopedCondition mutex( _cond );
94  _value |= value;
95  _cond.broadcast();
96  return *this;
97  }
98 
100  Monitor& operator &= ( const T& value )
101  {
102  ScopedCondition mutex( _cond );
103  _value &= value;
104  _cond.broadcast();
105  return *this;
106  }
107 
109  void set( const T& value )
110  {
111  ScopedCondition mutex( _cond );
112  _value = value;
113  _cond.broadcast();
114  }
116 
124  const T waitEQ( const T& value ) const
125  {
126  return _waitPredicate( boost::bind( std::equal_to<T>(), value, _1 ));
127  }
128 
134  const T waitNE( const T& value ) const
135  {
136  return _waitPredicate( boost::bind( std::not_equal_to<T>(), value, _1));
137  }
138 
144  const T waitNE( const T& v1, const T& v2 ) const
145  {
146  if( sizeof( T ) <= 8 ) // issue #1
147  {
148  const T current = _value;
149  if( current != v1 && current != v2 )
150  return current;
151  }
152  ScopedCondition mutex( _cond );
153  while( _value == v1 || _value == v2 )
154  _cond.wait();
155  return _value;
156  }
157 
163  const T waitGE( const T& value ) const
164  {
165  return _waitPredicate( boost::bind( std::greater_equal<T>(), _1,
166  value ));
167  }
168 
174  const T waitLE( const T& value ) const
175  { return _waitPredicate( boost::bind( std::less_equal<T>(), _1, value )); }
176 
182  const T waitGT( const T& value ) const
183  { return _waitPredicate( boost::bind( std::greater<T>(), _1, value )); }
184 
190  const T waitLT( const T& value ) const
191  { return _waitPredicate( boost::bind( std::less<T>(), _1, value )); }
192 
202  bool timedWaitEQ( const T& value, const uint32_t timeout ) const
203  {
204  return _timedWaitPredicate( boost::bind( std::equal_to<T>(), _1,
205  value ), timeout );
206  }
207 
215  bool timedWaitNE( const T& value, const uint32_t timeout ) const
216  {
217  return _timedWaitPredicate( boost::bind( std::not_equal_to<T>(), _1,
218  value ), timeout );
219  }
220 
228  bool timedWaitGE( const T& value, const uint32_t timeout ) const
229  {
230  return _timedWaitPredicate( boost::bind( std::greater_equal<T>(), _1,
231  value ), timeout );
232  }
233 
241  bool timedWaitLE( const T& value, const uint32_t timeout ) const
242  {
243  return _timedWaitPredicate( boost::bind( std::less_equal<T>(), _1,
244  value ), timeout );
245  }
246 
254  bool timedWaitGT( const T& value, const uint32_t timeout ) const
255  {
256  return _timedWaitPredicate( boost::bind( std::greater<T>(), _1,
257  value ), timeout );
258  }
259 
267  bool timedWaitLT( const T& value, const uint32_t timeout ) const
268  {
269  return _timedWaitPredicate( boost::bind( std::less<T>(), _1, value ),
270  timeout );
271  }
272 
274 
277  bool operator == ( const T& value ) const
278  {
279  ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
280  return _value == value;
281  }
282  bool operator != ( const T& value ) const
283  {
284  ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
285  return _value != value;
286  }
287  bool operator < ( const T& value ) const
288  {
289  ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
290  return _value < value;
291  }
292  bool operator > ( const T& value ) const
293  {
294  ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
295  return _value > value;
296  }
297  bool operator <= ( const T& value ) const
298  {
299  ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
300  return _value <= value;
301  }
302  bool operator >= ( const T& value ) const
303  {
304  ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
305  return _value >= value;
306  }
307 
308  bool operator == ( const Monitor<T>& rhs ) const
309  {
310  ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
311  return _value == rhs._value;
312  }
313  bool operator != ( const Monitor<T>& rhs ) const
314  {
315  ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
316  return _value != rhs._value;
317  }
318  bool operator < ( const Monitor<T>& rhs ) const
319  {
320  ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
321  return _value < rhs._value;
322  }
323  bool operator > ( const Monitor<T>& rhs ) const
324  {
325  ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
326  return _value > rhs._value;
327  }
328  bool operator <= ( const Monitor<T>& rhs ) const
329  {
330  ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
331  return _value <= rhs._value;
332  }
333  bool operator >= ( const Monitor<T>& rhs ) const
334  {
335  ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
336  return _value >= rhs._value;
337  }
339  operator bool_t()
340  {
341  ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
342  return _value ? &Monitor< T >::bool_true : 0;
343  }
345 
349  const T& operator->() const { return _value; }
350 
352  const T& get() const { return _value; }
353 
355  T operator + ( const T& value ) const
356  {
357  ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
358  return _value + value;
359  }
360 
362  T operator | ( const T& value ) const
363  {
364  ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
365  return static_cast< T >( _value | value );
366  }
367 
369  T operator & ( const T& value ) const
370  {
371  ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
372  return static_cast< T >( _value & value );
373  }
375 
376 private:
377  T _value;
378  mutable Condition _cond;
379 
380  template< typename F >
381  const T _waitPredicate( const F& predicate ) const
382  {
383  if( sizeof( T ) <= 8 ) // issue #1
384  {
385  const T current = _value;
386  if( predicate( current ))
387  return current;
388  }
389  ScopedCondition mutex( _cond );
390  while( !predicate( _value ))
391  _cond.wait();
392  return _value;
393  }
394 
395  template< typename F >
396  bool _timedWaitPredicate( const F& predicate, const uint32_t timeout ) const
397  {
398  if( sizeof( T ) <= 8 ) // issue #1
399  {
400  const T current = _value;
401  if( predicate( current ))
402  return true;
403  }
404  ScopedCondition mutex( _cond );
405  while( !predicate( _value ))
406  {
407  if( !_cond.timedWait( timeout ) )
408  {
409  return false;
410  }
411  }
412  return true;
413  }
414 };
415 
418 
420 template< typename T >
421 inline std::ostream& operator << ( std::ostream& os,
422  const Monitor<T>& monitor )
423 {
424  os << "Monitor< " << monitor.get() << " >";
425  return os;
426 }
427 
428 template<> inline Monitor< bool >& Monitor< bool >::operator++ ()
429 {
430  ScopedCondition mutex( _cond );
431  assert( !_value );
432  _value = !_value;
433  _cond.broadcast();
434  return *this;
435 }
436 
437 template<> inline Monitor< bool >& Monitor< bool >::operator-- ()
438 {
439  ScopedCondition mutex( _cond );
440  assert( !_value );
441  _value = !_value;
442  _cond.broadcast();
443  return *this;
444 }
445 
446 template<> inline
447 Monitor< bool >& Monitor< bool >::operator |= ( const bool& value )
448 {
449  if( value )
450  {
451  ScopedCondition mutex( _cond );
452  _value = value;
453  _cond.broadcast();
454  }
455  return *this;
456 }
457 }
458 
459 #include <servus/uint128_t.h>
460 namespace lunchbox
461 {
462 template<> inline Monitor< servus::uint128_t >::Monitor() {}
463 }
464 
465 #endif //LUNCHBOX_MONITOR_H
const T waitGE(const T &value) const
Block until the monitor has a value greater or equal to the given value.
Definition: monitor.h:163
bool timedWaitLT(const T &value, const uint32_t timeout) const
Block until the monitor has a value less than the given value.
Definition: monitor.h:267
LUNCHBOX_API bool timedWait(const uint32_t timeout)
Atomically unlock the mutex, wait for a signal and relock the mutex.
Basic type definitions not provided by the operating system.
A condition variable and associated lock.
Definition: condition.h:33
ScopedMutex< Condition, WriteOp > ScopedCondition
A scoped mutex for a write operation on a condition.
Definition: scopedMutex.h:126
const T & operator->() const
Definition: monitor.h:349
const T waitLT(const T &value) const
Block until the monitor has a value less than the given value.
Definition: monitor.h:190
Monitor< uint32_t > Monitoru
An unsigned 32bit integer monitor.
Definition: monitor.h:417
T operator|(const T &value) const
Definition: monitor.h:362
Monitor(const T &value)
Construct a new monitor with a given default value.
Definition: monitor.h:54
bool timedWaitGT(const T &value, const uint32_t timeout) const
Block until the monitor has a value greater than the given value.
Definition: monitor.h:254
const T waitLE(const T &value) const
Block until the monitor has a value less or equal to the given value.
Definition: monitor.h:174
Monitor & operator--()
Decrement the monitored value, prefix only.
Definition: monitor.h:74
const T waitNE(const T &value) const
Block until the monitor has not the given value.
Definition: monitor.h:134
bool timedWaitGE(const T &value, const uint32_t timeout) const
Block until the monitor has a value greater or equal to the given value.
Definition: monitor.h:228
Monitor< bool > Monitorb
A boolean monitor variable.
Definition: monitor.h:416
A monitor primitive.
Definition: monitor.h:44
const T waitNE(const T &v1, const T &v2) const
Block until the monitor has none of the given values.
Definition: monitor.h:144
bool timedWaitNE(const T &value, const uint32_t timeout) const
Block until the monitor has not the given value.
Definition: monitor.h:215
Monitor(const Monitor< T > &from)
Ctor initializing with the given monitor value.
Definition: monitor.h:57
Monitor & operator|=(const T &value)
Perform an or operation on the value.
Definition: monitor.h:91
Monitor & operator=(const T &value)
Assign a new value.
Definition: monitor.h:83
Monitor & operator&=(const T &value)
Perform an and operation on the value.
Definition: monitor.h:100
T operator&(const T &value) const
Definition: monitor.h:369
Monitor()
Construct a new monitor with a default value of 0.
Definition: monitor.h:51
LUNCHBOX_API void broadcast()
Broadcast the condition.
LUNCHBOX_API void wait()
Atomically unlock the mutex, wait for a signal and relock the mutex.
Abstraction layer and common utilities for multi-threaded programming.
Definition: algorithm.h:32
bool timedWaitEQ(const T &value, const uint32_t timeout) const
Block until the monitor has the given value.
Definition: monitor.h:202
void set(const T &value)
Set a new value.
Definition: monitor.h:109
std::ostream & operator<<(std::ostream &os, const Array< T > &array)
Pretty-print all members of the array.
Definition: array.h:47
bool timedWaitLE(const T &value, const uint32_t timeout) const
Block until the monitor has a value less or equal to the given value.
Definition: monitor.h:241
A scoped mutex.
Definition: scopedMutex.h:59
const T waitGT(const T &value) const
Block until the monitor has a value greater than the given value.
Definition: monitor.h:182
Monitor & operator++()
Increment the monitored value, prefix only.
Definition: monitor.h:65
T operator+(const T &value) const
Definition: monitor.h:355
~Monitor()
Destructs the monitor.
Definition: monitor.h:60
const T waitEQ(const T &value) const
Block until the monitor has the given value.
Definition: monitor.h:124
const T & get() const
Definition: monitor.h:352