HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
UT_Relacy.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_Relacy.h (UT Library, C++)
7  *
8  * COMMENTS: Wrapper classes for testing with Relacy.
9  *
10  * - Do NOT include this in .h files!
11  * - Only include this in the .C file of your unit tests.
12  * - Include this file *first* in your .C file so that it can
13  * redefine everything. For any conflicting header files,
14  * add them to the PRE_INCLUDES list below.
15  * - For all classes wrapped by this file, use the macro UT_VAR()
16  * to access the variables of these classes.
17  *
18  * For more information on the Relacy Race Detector see
19  * http://www.1024cores.net/home/relacy-race-detector
20  *
21  */
22 
23 #ifndef __UT_RELACY_INCLUDED__
24 #define __UT_RELACY_INCLUDED__
25 
26 #if !defined(UT_DEBUG_RELACY)
27 
28 //
29 // No Relacy
30 //
31 
32 #define UT_VAR(X) (X)
33 #define UT_VAR_T(X) X
34 
35 #define UT_LOG_EVENT(X)
36 
37 #else
38 
39 
40 // PRE_INCLUDES
41 // These headers must be included before we can perform the redefinitions to
42 // avoid compiler errors in the files that include UT_Relacy.h.
43 #include "UT_Assert.h"
44 #include "UT_ConcurrentVector.h"
45 #include "UT_Debug.h"
46 #include "UT_IntArray.h"
47 #include "UT_LockUtil.h"
48 #include "UT_ValArray.h"
49 #include "UT_RecursiveTimedLock.h"
50 #include "UT_Array.h"
51 #include "UT_SmallObject.h"
52 #include "UT_UniquePtr.h"
53 #include "UT_StopWatch.h"
54 #include "UT_String.h"
55 #include "UT_SysClone.h"
56 #include "UT_TaskLock.h"
57 #include "UT_TestManager.h"
58 #include "UT_Thread.h"
59 #include "UT_ThreadSpecificValue.h"
60 #include "UT_ValArray.h"
61 #include <SYS/SYS_AtomicInt.h>
62 #include <SYS/SYS_AtomicPtr.h>
63 #include <SYS/SYS_BoostThread.h>
64 #include <SYS/SYS_Math.h>
65 #include <SYS/SYS_StaticInit.h>
66 #include <SYS/SYS_Types.h>
67 #include <SYS/SYS_TypeTraits.h>
68 #include <limits>
69 #include <errno.h>
70 #include <stdio.h>
71 
72 
73 //
74 // Relacy
75 //
76 
77 #define RL_MSVC_OUTPUT // output debug message to MSVC
78 #define RL_DEBUGBREAK_ON_FAILURE // cause breakpoint on failures
79 
80 #include <relacy/relacy_std.hpp> // include Relacy
81 
82 namespace UT_Relacy
83 {
84 
85 // Import classes that we're using from Relacy into this namespace
86 using rl::debug_info;
87 using rl::debug_info_param;
88 using rl::atomic;
89 using rl::recursive_timed_mutex;
90 
91 //
92 // Wrapper for atomic variables
93 //
94 
95 #define SYS_MEMORY_ORDER_RELAXED (rl::mo_relaxed)
96 //#define SYS_MEMORY_ORDER_CONSUME (rl::mo_consume)
97 //#define SYS_MEMORY_ORDER_ACQUIRE (rl::mo_acquire)
98 //#define SYS_MEMORY_ORDER_RELEASE (rl::mo_release)
99 //#define SYS_MEMORY_ORDER_ACQ_REL (rl::mo_acq_rel)
100 #define SYS_MEMORY_ORDER_LOAD (rl::mo_acquire)
101 #define SYS_MEMORY_ORDER_STORE (rl::mo_release)
102 #define SYS_MEMORY_ORDER_SEQ_CST (rl::mo_seq_cst)
103 
104 template<typename T>
105 class SYS_Atomic;
106 
107 template<typename T>
108 class SYS_AtomicProxyConst
109 {
110 public:
111  SYS_AtomicProxyConst(SYS_Atomic<T> const & var, debug_info_param info)
112  : var_(const_cast<SYS_Atomic<T>&>(var))
113  , info_(info)
114  {
115  }
116 
117  T load(rl::memory_order mo = rl::mo_seq_cst) const
118  {
119  return var_.load(mo, info_);
120  }
121 
122  operator T () const
123  {
124  return load();
125  }
126 
127 protected:
128  SYS_Atomic<T>& var_;
129  debug_info info_;
130 
131  SYS_AtomicProxyConst& operator = (SYS_AtomicProxyConst const&);
132 };
133 
134 template<typename T>
135 class SYS_AtomicProxy : public SYS_AtomicProxyConst<T>
136 {
137 public:
138  SYS_AtomicProxy(SYS_Atomic<T> & var, debug_info_param info)
139  : SYS_AtomicProxyConst<T>(var, info)
140  {
141  }
142 
143  void store(T value, rl::memory_order mo = rl::mo_seq_cst)
144  {
145  this->var_.store(value, mo, this->info_);
146  }
147  T add(T value)
148  {
149  return this->var_.add(value, this->info_);
150  }
151  T exchange(T xchg)
152  {
153  return this->var_.exchange(xchg, this->info_);
154  }
155 };
156 
157 template <typename T>
158 class SYS_Atomic : private rl::generic_atomic<T, true>
159 {
160  typedef rl::generic_atomic<T, true> SUPER;
161 
162 public:
163  SYS_Atomic()
164  {
165  }
166 
167  SYS_Atomic(T value)
168  {
169  SUPER::store(value, rl::mo_relaxed, $);
170  }
171 
172  void store(T val, rl::memory_order mo, rl::debug_info_param info)
173  {
174  SUPER::store(val, mo, info);
175  }
176  T load(rl::memory_order mo, rl::debug_info_param info) const
177  {
178  return SUPER::load(mo, info);
179  }
180  T add(T val, rl::debug_info_param info)
181  {
182  return SUPER::fetch_add(val, rl::mo_seq_cst, info) + val;
183  }
184  T exchange(T val, rl::debug_info_param info)
185  {
186  return SUPER::exchange(val, rl::mo_seq_cst, info);
187  }
188 
189  SYS_AtomicProxyConst<T> operator () (debug_info_param info) const
190  {
191  return SYS_AtomicProxyConst<T>(*this, info);
192  }
193 
194  SYS_AtomicProxy<T> operator () (debug_info_param info)
195  {
196  return SYS_AtomicProxy<T>(*this, info);
197  }
198 
199  friend class SYS_AtomicProxy<T>;
200  friend class SYS_AtomicProxyConst<T>;
201 
202  RL_NOCOPY(SYS_Atomic);
203 };
204 
205 typedef SYS_Atomic<int32> SYS_AtomicInt32; // From SYS_AtomicInt.h
206 
207 template <typename T>
208 class SYS_AtomicPtr : public SYS_Atomic<T *> // From SYS_AtomicPtr.h
209 {
210 public:
211 
212  SYS_AtomicPtr(T *ptr = NULL)
213  : SYS_Atomic(ptr)
214  {
215  }
216 
217 };
218 
219 inline int
220 SYSgetSTID()
221 {
222  return rl::ctx().current_thread()
223  + UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX;
224 }
225 
226 class UT_RelacyObject
227 {
228 public:
229  virtual ~UT_RelacyObject() { }
230  virtual void construct(int num_threads) = 0;
231  virtual void destruct() = 0;
232 };
233 
234 class UT_RelacyManager
235 {
236 public:
237  UT_RelacyManager()
238  : myNumThreads(0)
239  {
240  }
241 
242  void subscribe(UT_RelacyObject &obj)
243  {
244  mySubscribers.append(&obj);
245  if (myNumThreads > 0)
246  obj.construct(myNumThreads);
247  }
248  void unsubscribe(UT_RelacyObject &obj)
249  {
250  if (myNumThreads > 0)
251  obj.destruct();
252  mySubscribers.findAndRemove(&obj);
253  }
254 
255  void construct(int num_threads)
256  {
257  myNumThreads = num_threads;
258  for (int i = 0; i < mySubscribers.entries(); i++)
259  mySubscribers(i)->construct(num_threads);
260  }
261 
262  void destruct()
263  {
264  for (int i = 0; i < mySubscribers.entries(); i++)
265  mySubscribers(i)->destruct();
266  myNumThreads = 0;
267  }
268 
269 private:
270  UT_ValArray<UT_RelacyObject *> mySubscribers;
271  int myNumThreads;
272 };
273 static UT_RelacyManager theRelacyManager;
274 
275 template <typename T>
276 class UT_ThreadSpecificValue : public UT_RelacyObject
277 {
278 public:
280  : myValues(NULL)
281  , myNumThreads(0)
282  {
283  theRelacyManager.subscribe(*this);
284  }
286  {
287  theRelacyManager.unsubscribe(*this);
288  }
289 
290  virtual void construct(int num_threads)
291  {
292  myValues = new T[num_threads];
293  myNumThreads = num_threads;
294 
295  // If T is an object, the default constructor will have been
296  // called. Otherwise, initialize the memory to 0.
297  if (std::numeric_limits<T>::is_specialized
299  {
300  memset(static_cast<void *>(myValues), 0, myNumThreads*sizeof(T));
301  }
302  }
303  virtual void destruct()
304  {
305  delete [] myValues;
306  myValues = NULL;
307  myNumThreads = 0;
308  }
309 
310  T &getValueForThread(int thread_index)
311  {
312  thread_index -= UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX;
313  UT_ASSERT(thread_index >= 0 && thread_index < myNumThreads);
314  return myValues[thread_index];
315  }
316 
317  const T &getValueForThread(int thread_index) const
318  {
319  thread_index -= UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX;
320  UT_ASSERT(thread_index >= 0 && thread_index < myNumThreads);
321  return myValues[thread_index];
322  }
323 
324  int maxThreadsSeen() const
325  {
326  return myNumThreads;
327  }
328 
329  class const_iterator
330  {
331  public:
332  const_iterator()
333  : myVal(0)
334  , myI(0)
335  , myEnd(0)
336  {
337  }
338  const_iterator(const const_iterator &copy)
339  : myVal(copy.myVal)
340  , myI(copy.myI)
341  , myEnd(copy.myEnd)
342  {
343  }
344  const_iterator &operator=(const const_iterator &copy)
345  {
346  if (this != &copy)
347  {
348  myVal = copy.myVal;
349  myI = copy.myI;
350  myEnd = copy.myEnd;
351  }
352  return *this;
353  }
354 
355  const T &get() const
356  {
357  return myVal->getValueForThread(myI);
358  }
359 
360  int thread() const
361  {
362  return myI;
363  }
364 
365  const_iterator &operator++()
366  {
367  if (myI < myEnd)
368  ++myI;
369  return *this;
370  }
371 
372  bool operator==(const const_iterator &right)
373  {
374  return (myVal == right.myVal
375  && myI == right.myI
376  && myEnd == right.myEnd);
377  }
378  bool operator!=(const const_iterator &right)
379  {
380  return !(*this == right);
381  }
382 
383  protected:
384  const_iterator(UT_ThreadSpecificValue<T> *value, int start)
385  : myVal(value)
386  , myI(start)
387  , myEnd(UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX
388  + value->maxThreadsSeen())
389  {
390  }
391 
393  int myI;
394  int myEnd;
395  template <typename TY> friend class UT_ThreadSpecificValue;
396  };
397 
398  /// iterator
399  ///
400  /// @note The iterator iterates over ALL possible thread values, thus
401  /// you must be aware that the get() method will return the default value
402  /// for cases where this variable was never used in a thread.
403  class iterator : public const_iterator
404  {
405  public:
406  iterator()
407  : const_iterator()
408  {
409  }
410  iterator(const iterator &copy)
411  : const_iterator(copy)
412  {
413  }
414  iterator &operator=(const iterator &copy)
415  {
416  this->const_iterator::operator=(copy);
417  return *this;
418  }
419 
420 
421  T &get()
422  {
423  return const_iterator::myVal->getValueForThread(
424  const_iterator::myI);
425  }
426 
427  iterator &operator++()
428  {
429  if (const_iterator::myI < const_iterator::myEnd)
430  ++const_iterator::myI;
431  return *this;
432  }
433 
434  bool operator==(const iterator &right)
435  {
436  return (const_iterator::myVal == right.myVal
437  && const_iterator::myI == right.myI
438  && const_iterator::myEnd == right.myEnd);
439  }
440  bool operator!=(const iterator &right)
441  {
442  return !(*this == right);
443  }
444 
445  private:
446  iterator(UT_ThreadSpecificValue<T> *value, int start)
447  : const_iterator(value, start)
448  {
449  }
450  template <typename TY> friend class UT_ThreadSpecificValue;
451  };
452 
453  /// begin() const iterator
454  const_iterator begin() const
455  { return const_iterator(this,
456  UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX); }
457  /// end() const iterator
458  const_iterator end() const
459  { return const_iterator(this,
460  UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX + maxThreadsSeen()); }
461 
462  /// begin() iterator
463  iterator begin()
464  { return iterator(this, UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX); }
465  /// end() iterator
466  iterator end()
467  { return iterator(this,
468  UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX + maxThreadsSeen()); }
469 
470 private:
471  T * myValues;
472  int myNumThreads;
473 };
474 
475 class UT_RecursiveTimedLockProxy
476 {
477 public:
478  UT_RecursiveTimedLockProxy(
479  recursive_timed_mutex &mutex,
480  debug_info_param info
481  )
482  : mutex_(mutex)
483  , info_(info)
484  {
485  }
486 
487  bool timedLock(int ms) { return mutex_.timed_lock(ms, info_); }
488  bool tryLock() { return mutex_.try_lock(info_); }
489  void lock() { mutex_.lock(info_); }
490  void unlock() { mutex_.unlock(info_); }
491 
492 private:
493  recursive_timed_mutex & mutex_;
494  debug_info info_;
495 };
496 
498 {
499 public:
501  {
502  }
503 
504  UT_RecursiveTimedLockProxy operator()(debug_info_param info)
505  {
506  return UT_RecursiveTimedLockProxy(mutex_, info);
507  }
508 
509 private:
510  recursive_timed_mutex mutex_;
511 
512  RL_NOCOPY(UT_RecursiveTimedLock);
513 };
514 
515 } // namespace UT_Relacy
516 
517 //
518 // Defines to swap in use of the wrappers
519 //
520 #define SYSgetSTID UT_Relacy::SYSgetSTID
521 #define UT_RecursiveTimedLock UT_Relacy::UT_RecursiveTimedLock
522 #define UT_ThreadSpecificValue UT_Relacy::UT_ThreadSpecificValue
523 #define SYS_AtomicInt32 UT_Relacy::SYS_AtomicInt32
524 #define SYS_AtomicPtr UT_Relacy::SYS_AtomicPtr
525 
526 // Substitute UT_ASSERT() with RL_ASSERT()
527 #ifdef UT_ASSERT
528  #undef UT_ASSERT
529 #endif
530 #define UT_ASSERT RL_ASSERT
531 
532 // Relacy specific macros
533 #define UT_LOG_EVENT(X) if (rl::ctx().collecting_history()) { RL_LOG(X); }
534 #define UT_VAR(X) VAR((X))
535 #define UT_VAR_T(X) VAR_T(X)
536 
537 #endif // UT_DEBUG_RELACY
538 
539 
540 //////////////////////////////////////////////////////////////////////////////
541 //
542 // UT_RelacyTest
543 //
544 
545 #ifdef UT_DEBUG_RELACY
546 
547 template <typename DERIVED_T, int THREAD_COUNT>
548 class UT_RelacyTest : public rl::test_suite<DERIVED_T, THREAD_COUNT>
549 {
550 public:
551  static bool simulate(int ITER_COUNT_RELACTY)
552  {
553  rl::test_params params;
554 
555  params.iteration_count = ITER_COUNT_RELACY;
556  params.search_type = rl::random_scheduler_type;
557  params.execution_depth_limit = 4000;
558  //
559  //params.iteration_count = 1;
560  //params.search_type = rl::fair_context_bound_scheduler_type;
561  //
562  //params.iteration_count = 1;
563  //params.search_type = rl::fair_full_search_scheduler_type;
564 
565  return rl::simulate<DERIVED_T>(params);
566  }
567 
568 protected:
569  void construct()
570  {
571  UT_Relacy::theRelacyManager.construct(THREAD_COUNT);
572  }
573  void destruct()
574  {
575  UT_Relacy::theRelacyManager.destruct();
576  }
577 
578  void fail()
579  {
580  UT_ASSERT(!"Test failed");
581  }
582 
583  // In Relacy, random timer's are already occurring so just skip
584  // this step algother.
585  void setSeed(unsigned int /*seed*/)
586  {
587  }
588  void sleepRandom(unsigned int /*max_millisec*/)
589  {
590  }
591 
592  int getMaxThreadId(int num_threads) const
593  {
594  return num_threads - 1;
595  }
596 
597 private:
598 };
599 
600 #else
601 
602 #include "UT_Assert.h"
603 #include "UT_ValArray.h"
604 #include "UT_Thread.h"
605 #include "UT_StopWatch.h"
606 #include "UT_String.h"
607 #include "UT_SysClone.h"
608 #include "UT_UniquePtr.h"
609 #include <SYS/SYS_Math.h>
610 #include <typeinfo>
611 
612 namespace UT_Relacy
613 {
614 
616 {
617 public:
619  : mySize(0)
620  {
621  }
623  {
624  for (int i = 0; i < myThreads.entries(); i++)
625  delete myThreads(i);
626  }
627 
628  void resize(int count)
629  {
630  mySize = count;
631 
632  // always grow array to maximum requested count
633  for (int i = myThreads.entries(); i < count; i++)
634  {
636  thr->startThread(0,0);
637  myThreads.append(thr);
638  }
639  UT_ASSERT(count <= myThreads.entries());
640  }
641 
643  {
644  UT_ASSERT(i >= 0 && i < mySize);
645  return myThreads(i);
646  }
647 
648  void waitThreads()
649  {
650  for (int i = 0; i < mySize; i++)
651  myThreads(i)->waitForState(UT_Thread::ThreadIdle);
652  }
653 
654  static ThreadPool *get(int count)
655  {
656  ThreadPool *&pool = getPoolPtr();
657 
658  if (!pool)
659  pool = new ThreadPool;
660 
661  pool->resize(count);
662  return pool;
663  }
664 
665  static void destroy()
666  {
667  ThreadPool *&pool = getPoolPtr();
668  delete pool;
669  pool = NULL;
670  }
671 
672 private:
673  static ThreadPool *&getPoolPtr()
674  {
675  static ThreadPool *thePool = NULL;
676  return thePool;
677  }
678 
679  UT_ValArray<UT_Thread *> myThreads;
680  int mySize;
681 };
682 
683 template <typename T>
685 {
687  int myIndex;
688 
689  static void *func(void *data)
690  {
691  ThreadData<T> * me = (ThreadData<T> *)data;
692  int i = me->myIndex;
693 
694  me->myTest->mySeqThreadIndex[i] = SYSgetSTID();
695  me->myTest->thread(i);
696  return NULL;
697  }
698 };
699 
700 } // namespace UT_Relacy
701 
702 template <typename DERIVED_T, int THREAD_COUNT>
704 {
705 public:
707 
708 
709  static bool simulate(int ITER_COUNT, bool verbose)
710  {
712  pool = UT_Relacy::ThreadPool::get(THREAD_COUNT);
713  bool passed = true;
715  UT_String num;
716 
717  if (verbose)
718  ts.reset(new UT_Timer(typeid(DERIVED_T).name()));
719 
720  for (int iter = 0; iter < ITER_COUNT; iter++)
721  {
722  DERIVED_T test;
724 
725  for (int i = 0; i < THREAD_COUNT; i++)
726  {
727  data[i].myTest = &test;
728  data[i].myIndex = i;
729  }
730 
731  test.myOk = true;
732  test.before();
733 
734  for (int i = 0; i < THREAD_COUNT; i++)
735  {
736  UT_Thread * thr = pool->getThread(i);
737 
739  &data[i]))
740  {
741  UT_ASSERT(!"Failed to start thread");
742  passed = false;
743  break;
744  }
745  }
746  pool->waitThreads();
747 
748  test.after();
749  if (!test.myOk)
750  passed = false;
751  }
752 
753  num.itoa(ITER_COUNT);
754  if (ts)
755  ts->timeStamp("iterations", num);
756  return passed;
757  }
758 
759 protected:
760  void construct()
761  {
762  mySeed = (int32)(((size_t)this) & 0xFFFFFFFF);
763  }
764  void destruct()
765  {
766  }
767 
768  void fail()
769  {
770  UT_ASSERT(!"Test failed");
771  myOk = false;
772  }
773 
774  void sleepRandom(unsigned int max_millisec)
775  {
776  UTnap((unsigned)(SYSrandom(mySeed)*max_millisec));
777  }
778 
779  int getMaxThreadId(int num_threads) const
780  {
781  int max_id = 0;
782  int max_value = mySeqThreadIndex[max_id];
783 
784  for (int i = 1; i < num_threads; i++)
785  {
786  if (mySeqThreadIndex[i] > max_value)
787  {
788  max_value = mySeqThreadIndex[i];
789  max_id = i;
790  }
791  }
792 
793  return max_id;
794  }
795 
796 private:
797  uint mySeed;
798  int mySeqThreadIndex[THREAD_COUNT];
799  bool myOk;
800 
801  template <typename T> friend struct UT_Relacy::ThreadData;
802 };
803 
804 #endif // UT_DEBUG_RELACY
805 
806 
807 #endif // __UT_RELACY_INCLUDED__
cvex test(vector P=0;int unbound=3;export float s=0;export vector Cf=0;)
Definition: test.vfl:11
void fail()
Definition: UT_Relacy.h:768
UT_Thread * getThread(int i)
Definition: UT_Relacy.h:642
GLuint start
Definition: glcorearb.h:474
png_voidp ptr
Definition: png.h:2145
void sleepRandom(unsigned int max_millisec)
Definition: UT_Relacy.h:774
SYS_AtomicInt< int32 > SYS_AtomicInt32
Definition: SYS_AtomicInt.h:80
png_uint_32 i
Definition: png.h:2877
bool operator==(const BaseDimensions< T > &a, const BaseDimensions< Y > &b)
Definition: Dimensions.h:137
Lock adapter for std mutexes.
static ThreadPool * get(int count)
Definition: UT_Relacy.h:654
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:102
GLuint GLuint end
Definition: glcorearb.h:474
int getMaxThreadId(int num_threads) const
Definition: UT_Relacy.h:779
static bool simulate(int ITER_COUNT, bool verbose)
Definition: UT_Relacy.h:709
virtual bool startThread(UTthreadFunc func, void *data, int stacksize)=0
void resize(int count)
Definition: UT_Relacy.h:628
GLboolean * data
Definition: glcorearb.h:130
GLuint const GLchar * name
Definition: glcorearb.h:785
static void destroy()
Definition: UT_Relacy.h:665
UT_RelacyTest< DERIVED_T, THREAD_COUNT > TestThread
Definition: UT_Relacy.h:706
int int32
Definition: SYS_Types.h:34
unsigned int uint
Definition: SYS_Types.h:39
static int itoa(char *str, int64 i)
GLint GLsizei count
Definition: glcorearb.h:404
exint entries() const
Alias of size(). size() is preferred.
Definition: UT_Array.h:446
static UT_Thread * allocThread(SpinMode spin_mode)
GLsizei const GLfloat * value
Definition: glcorearb.h:823
SYS_API int SYSgetSTID()
void destruct()
Definition: UT_Relacy.h:764
A smart pointer for unique ownership of dynamically allocated objects.
Definition: UT_UniquePtr.h:47
GLuint GLfloat * val
Definition: glcorearb.h:1607
GLenum const GLfloat * params
Definition: glcorearb.h:104
exint append(void)
Definition: UT_Array.h:95
png_infop png_uint_32 int num
Definition: png.h:2158
bool operator!=(const BaseDimensions< T > &a, const BaseDimensions< Y > &b)
Definition: Dimensions.h:165
void construct()
Definition: UT_Relacy.h:760
static void * func(void *data)
Definition: UT_Relacy.h:689
UT_StdLockable< std::recursive_timed_mutex > UT_RecursiveTimedLock
const_iterator begin() const
begin() const iterator