OpendTect-6_4  6.4
atomic.h
Go to the documentation of this file.
1 #ifndef atomic_h
2 #define atomic_h
3 
4 /*
5 ________________________________________________________________________
6 
7  (C) dGB Beheer B.V.; (LICENSE) http://opendtect.org/OpendTect_license.txt
8  Author: K. Tingdahl
9  Date: 9-3-1999
10  RCS: $Id$
11 ________________________________________________________________________
12 
13 */
14 
15 #include "basicmod.h"
16 #include "commondefs.h"
17 #include "plftypes.h"
18 #include "odversion.h"
19 
20 #ifdef __win__
21 # define __WINATOMICS__
22 # include <Windows.h>
23 # include "thread.h"
24 #else
25 # define __GCCATOMICS__
26 #endif
27 
28 namespace Threads {
29 
30 class Mutex;
31 
32 template <class T>
33 mClass(Basic) Atomic
34 {
35 public:
36 
37  Atomic(T val=0);
38  Atomic(const Atomic&);
39  ~Atomic();
40 
41  operator T() const { return get(); }
42  T get() const;
43 
44  T operator=(T v);
45  T operator=(const Atomic<T>& v) { return operator=(v.get()); }
46 
47  inline T operator+=(T);
48  inline T operator-=(T);
49  inline T operator++();
50  inline T operator--();
51  inline T operator++(int);
52  inline T operator--(int);
53 
54  inline T exchange(T newval);
57 #if mODVersion < 700
58  //Force developers to adapt code in od6
59  inline bool setIfValueIs(T curval,T newval,T* actualvalptr);
60 #else
61  inline bool setIfValueIs(T curval,T newval,T* actualvalptr = 0);
62 #endif
63 
71 private:
72 
73 #ifdef __STDATOMICS__
74  std::atomic<T> val_;
75 #elif (defined __WINATOMICS__)
76  volatile T values_[8];
77  volatile T* valptr_;
78 
79  Mutex* lock_;
80 
81 #else
82  volatile T val_;
83 #endif
84 public:
85  const void* getStorage() const;
87 };
88 
89 
98 #if mODVersion < 700
99 inline bool atomicSetIfValueIs( volatile int& val, int curval, int newval,
100  int* actualvalptr )
101 //Force developers to adapt code in od6
102 #else
103 inline bool atomicSetIfValueIs( volatile int& val, int curval, int newval,
104  int* actualvalptr = 0 )
105 #endif
106 {
107 # ifdef __win__
108  const int oldval =InterlockedCompareExchange( (volatile long*) &val, newval,
109  curval );
110  if ( oldval!=curval )
111  {
112  if ( actualvalptr ) *actualvalptr = oldval;
113  return false;
114  }
115 
116  return true;
117 
118 # else
119  const int old = __sync_val_compare_and_swap( &val, curval, newval );
120  if ( old!=curval )
121  {
122  if ( actualvalptr ) *actualvalptr = old;
123  return false;
124  }
125 
126  return true;
127 #endif
128 }
129 
130 
131 #ifdef __win__
132 #define mAtomicPointerType long long
133 #else
134 #define mAtomicPointerType T*
135 #endif
136 
137 
143 template <class T>
145 {
146 public:
147  inline AtomicPointer(T* newptr = 0);
148 
149  inline bool setIfEqual(const T* curptr, T* newptr);
157  AtomicPointer<T>& operator=(T* ptr);
158  AtomicPointer<T>& operator=(const AtomicPointer<T>&);
159 
160  inline T* setToNull();
163  T* exchange(T* newptr);
164  //*!<\returns old value
165 
166  inline operator T*() const;
167  inline T* operator->();
168  inline const T* operator->() const;
169 
170  inline T* operator+=(int);
171  inline T* operator-=(int);
172  inline T* operator++();
173  inline T* operator--();
174  inline T* operator++(int);
175  inline T* operator--(int);
176 
177 private:
179  { }
180 
182 
183 public:
184  const void* getStorage() const
185  {
186  return (void*) ptr_.getStorage();
187  }
189 };
190 
191 
201 {
202 public:
203  SpinLock(bool recursive = false);
204  /*\If recursive, mutex can be locked
205  multiple times from the same thread without deadlock.
206  It will be unlock when unLock has been called the same
207  number of times as lock(). */
208  SpinLock(const SpinLock&);
209  ~SpinLock();
210 
211  SpinLock& operator=(const SpinLock& b)
212  { recursive_ = b.recursive_; return *this; }
213 
214  void lock();
215  void unLock();
216  bool tryLock();
217 
218 protected:
222  int count_;
224 
225 public:
226  int count() const { return count_; }
228 };
229 
230 
231 //Implementations
232 
233 #ifdef __STDATOMICS__
234 template <class T> inline
235 Atomic<T>::Atomic( T val )
236  : val_( val )
237 {}
238 
239 template <class T> inline
240 Atomic<T>::Atomic( const Atomic<T>& oth )
241  : val_( oth.val_ )
242 {
243 }
244 
245 
246 template <class T> inline
247 Atomic<T>::Atomic( const Atomic<T>& val )
248  : val_( val.get() )
249 {}
250 
251 
252 template <class T> inline
253 const void* Atomic<T>::getStorage() const
254 {
255  return (const void*) &val_;
256 }
257 
258 
259 template <class T> inline
261 {
262  return val_ += b;
263 }
264 
265 
266 template <class T> inline
268 {
269  return val_ -= b;
270 }
271 
272 
273 template <class T> inline
275 {
276  return ++val_;
277 }
278 
279 
280 template <class T> inline
282 {
283  return --val_;
284 }
285 
286 
287 template <class T> inline
289 {
290  return val_++;
291 }
292 
293 
294 template <class T> inline
296 {
297  return val_--;
298 }
299 
300 
301 template <class T> inline
302 bool Atomic<T>::setIfValueIs( T curval, T newval, T* actualvalptr )
303 {
304  T presumedval = curval;
305  if ( !val_.compare_exchange_strong( presumedval, newval ) && actualvalptr )
306  {
307  *actualvalptr = presumedval;
308  return false;
309  }
310 
311  return true;
312 }
313 
314 
315 template <class T> inline
316 T Atomic<T>::exchange( T newval )
317 {
318  return val_.exchange( newval );
319 }
320 
321 
322 #endif //STDATOMICS
323 
324 #ifdef __GCCATOMICS__
325 template <class T> inline
327  : val_( val )
328 {}
329 
330 template <class T> inline
332  : val_( oth.val_ )
333 {
334 }
335 
336 template <class T> inline
337 Atomic<T>::~Atomic<T>()
338 {}
339 
340 
341 template <class T> inline
342 T Atomic<T>::get() const
343 {
344  return val_;
345 }
346 
347 
348 template <class T> inline
350 {
351  val_ = val;
352  return val_;
353 }
354 
355 
356 template <class T> inline
358 {
359  return __sync_add_and_fetch(&val_, b);
360 }
361 
362 
363 template <class T> inline
365 {
366  return __sync_sub_and_fetch(&val_, b);
367 }
368 
369 
370 template <class T> inline
372 {
373  return __sync_add_and_fetch(&val_, 1);
374 }
375 
376 
377 template <class T> inline
379 {
380  return __sync_sub_and_fetch(&val_, 1);
381 }
382 
383 
384 template <class T> inline
386 {
387  return __sync_fetch_and_add(&val_, 1);
388 }
389 
390 
391 template <class T> inline
393 {
394  return __sync_fetch_and_sub(&val_, 1);
395 }
396 
397 template <class T> inline
398 bool Atomic<T>::setIfValueIs(T curval, T newval, T* actualvalptr )
399 {
400  const T old = __sync_val_compare_and_swap( &val_, curval, newval );
401  if ( old!=curval )
402  {
403  if ( actualvalptr ) *actualvalptr = old;
404  return false;
405  }
406 
407  return true;
408 }
409 
410 
411 template <> inline
412 bool Atomic<int>::setIfValueIs( int curval, int newval, int* actualvalptr )
413 {
414  return atomicSetIfValueIs( val_, curval, newval, actualvalptr );
415 }
416 
417 
418 template <class T> inline
419 T Atomic<T>::exchange( T newval )
420 {
421  return __sync_lock_test_and_set( &val_, newval );
422 }
423 
424 
425 template <class T> inline
426 const void* Atomic<T>::getStorage() const
427 {
428  return (const void*) &val_;
429 }
430 
431 
432 #endif //__GCCATOMICS__
433 
434 
435 
436 #ifdef __WINATOMICS__
437 
438 
439 template <class T> inline
440 Atomic<T>::Atomic( T val )
441  : lock_( new Mutex )
442  , valptr_( values_ )
443 {
444  *valptr_ = val;
445 }
446 
447 template <class T> inline
448 Atomic<T>::Atomic( const Atomic<T>& oth )
449  : lock_( new Mutex )
450  , valptr_( values_ )
451 {
452  *this = (T)oth;
453 }
454 
455 template <class T> inline
456 const void* Atomic<T>::getStorage() const
457 {
458  return (const void*) valptr_;
459 }
460 
461 
462 template <class T> inline
464 {
465  delete lock_;
466 }
467 
468 
469 template <class T> inline
470 T Atomic<T>::get() const
471 {
472  return *valptr_;
473 }
474 
475 
476 template <class T> inline
477 T Atomic<T>::exchange( T newval )
478 {
479  T curval = *valptr_;
480  while ( !setIfValueIs( curval, newval, &curval ) )
481  {}
482 
483  return curval;
484 }
485 
486 
487 template <class T> inline
488 T Atomic<T>::operator=(T val)
489 {
490  *valptr_ = val;
491  return *valptr_;
492 }
493 
494 
495 template <class T> inline
497 {
498  MutexLocker lock( *lock_ );
499  return (*valptr_) += b;
500 }
501 
502 
503 template <class T> inline
505 {
506  MutexLocker lock( *lock_ );
507  return (*valptr_) -= b;
508 }
509 
510 
511 template <class T> inline
513 {
514  MutexLocker lock( *lock_ );
515  return ++(*valptr_);
516 }
517 
518 
519 template <class T> inline
521 {
522  MutexLocker lock( *lock_ );
523  return --(*valptr_);
524 }
525 
526 
527 template <class T> inline
529 {
530  MutexLocker lock( *lock_ );
531  return (*valptr_)++;
532 }
533 
534 
535 template <class T> inline
537 {
538  MutexLocker lock( *lock_ );
539  return (*valptr_)--;
540 }
541 
542 
543 
544 template <class T> inline
545 bool Atomic<T>::setIfValueIs(T curval, T newval, T* actualvalptr )
546 {
547  MutexLocker lock( *lock_ );
548  const bool res = (*valptr_)==curval;
549  if ( res )
550  (*valptr_) = newval;
551  else if ( actualvalptr ) *actualvalptr = (*valptr_);
552 
553  return res;
554 }
555 
556 
557 #ifdef __win64__
558 
559 template <> inline
560 Atomic<long long>::Atomic( long long val )
561  : lock_( 0 )
562 {
563  valptr_ = &values_[0];
564  while ( ((long long) valptr_) % 64 )
565  valptr_++;
566 
567  *valptr_ = val;
568 }
569 
570 
571 template <> inline
572 bool Atomic<long long>::setIfValueIs(long long curval, long long newval,
573  long long* actualvalptr )
574 {
575  const long long prevval =
576  InterlockedCompareExchange64(valptr_,newval,curval);
577  if ( prevval==curval )
578  return true;
579  if ( actualvalptr ) *actualvalptr = prevval;
580  return false;
581 }
582 
583 
584 template <> inline
585 long long Atomic<long long>::operator += (long long b)
586 {
587  return InterlockedAdd64( valptr_, b );
588 }
589 
590 
591 template <> inline
592 long long Atomic<long long>::operator -= (long long b)
593 {
594  return InterlockedAdd64( valptr_, -b );
595 }
596 
597 
598 template <> inline
600 {
601  return InterlockedIncrement64( valptr_ );
602 }
603 
604 
605 template <> inline
607 {
608  return InterlockedDecrement64( valptr_ );
609 }
610 
611 
612 template <> inline
613 long long Atomic<long long>::operator ++(int)
614 {
615  return InterlockedIncrement64( valptr_ )-1;
616 }
617 
618 
619 template <> inline
620 long long Atomic<long long>::exchange(long long newval)
621 {
622  return InterlockedExchange64( valptr_, newval );
623 }
624 
625 
626 template <> inline
627 long long Atomic<long long>::operator -- (int)
628 {
629  return InterlockedDecrement64( valptr_ )+1;
630 }
631 
632 
633 # endif //not win32
634 
635 template <> inline
636 Atomic<int>::Atomic( int val )
637  : lock_( 0 )
638 {
639  valptr_ = &values_[0];
640  while ( ((int) valptr_) % 32 )
641  valptr_++;
642 
643  *valptr_ = val;
644 }
645 
646 
647 template <> inline
648 bool Atomic<int>::setIfValueIs( int curval, int newval, int* actualvalptr )
649 {
650  const int prevval =
651  InterlockedCompareExchange((volatile long*) valptr_,newval,curval);
652  if ( prevval==curval )
653  return true;
654  if ( actualvalptr ) *actualvalptr = prevval;
655 
656  return false;
657 }
658 
659 
660 template <> inline
661 int Atomic<int>::operator += (int b)
662 {
663  return InterlockedExchangeAdd( (volatile long*) valptr_, b ) + b;
664 }
665 
666 
667 template <> inline
668 int Atomic<int>::operator -= (int b)
669 {
670  return InterlockedExchangeAdd( (volatile long*) valptr_, -b ) -b;
671 }
672 
673 
674 template <> inline
676 {
677  return InterlockedIncrement( (volatile long*) valptr_ );
678 }
679 
680 
681 template <> inline
683 {
684  return InterlockedDecrement( (volatile long*) valptr_ );
685 }
686 
687 
688 template <> inline
690 {
691  return InterlockedIncrement( (volatile long*) valptr_ )-1;
692 }
693 
694 
695 template <> inline
696 int Atomic<int>::exchange(int newval)
697 {
698  return InterlockedExchange( (volatile long*) valptr_, newval );
699 }
700 
701 
702 template <> inline
704 {
705  return InterlockedDecrement( (volatile long*) valptr_ )+1;
706 }
707 
708 
709 template <> inline
710 Atomic<long>::Atomic( long val )
711  : lock_( 0 )
712 {
713  valptr_ = &values_[0];
714  while ( ((long long) valptr_) % 32 )
715  valptr_++;
716 
717  *valptr_ = val;
718 }
719 
720 
721 template <> inline
722 bool Atomic<long>::setIfValueIs( long curval, long newval, long* actualvalptr )
723 {
724  const long prevval =
725  InterlockedCompareExchange( valptr_, newval, curval );
726  if ( prevval==curval )
727  return true;
728  if ( actualvalptr ) *actualvalptr = prevval;
729  return false;
730 }
731 
732 
733 template <> inline
734 long Atomic<long>::operator += (long b)
735 {
736  return InterlockedExchangeAdd( valptr_, (long) b ) + b;
737 }
738 
739 
740 template <> inline
741 long Atomic<long>::operator -= (long b)
742 {
743  return InterlockedExchangeAdd( valptr_, -b ) - b;
744 }
745 
746 
747 template <> inline
749 {
750  return InterlockedIncrement( valptr_ );
751 }
752 
753 
754 template <> inline
756 {
757  return InterlockedDecrement( valptr_ );
758 }
759 
760 
761 template <> inline
763 {
764  return InterlockedIncrement( valptr_ )-1;
765 }
766 
767 
768 template <> inline
769 long Atomic<long>::exchange(long newval)
770 {
771  return InterlockedExchange( valptr_, newval );
772 }
773 
774 
775 template <> inline
777 {
778  return InterlockedDecrement( valptr_ )+1;
779 }
780 
781 
782 #endif //__WINATOMICS__
783 
784 /* AtomicPointer implementations. */
785 template <class T> inline
787  : ptr_( (mAtomicPointerType) newptr )
788 {}
789 
790 
791 template <class T> inline
792 bool AtomicPointer<T>::setIfEqual( const T* oldptr, T* newptr )
793 {
794  mAtomicPointerType curval = (mAtomicPointerType) oldptr;
795  return ptr_.setIfValueIs( curval, (mAtomicPointerType) newptr, 0 );
796 }
797 
798 
799 template <class T> inline
801 {
802  return (T*) ptr_.exchange( (mAtomicPointerType) newptr );
803 }
804 
805 
806 template <class T> inline
808 {
810  while ( oldptr && !ptr_.setIfValueIs( oldptr, 0, &oldptr ) )
811  {}
812 
813  return (T*) oldptr;
814 }
815 
816 
817 template <class T> inline
819 {
820  ptr_ = (mAtomicPointerType)ptr;
821  return *this;
822 }
823 
824 
825 template <class T> inline
827 {
828  return operator=((T*)ptr);
829 }
830 
831 
832 template <class T> inline
833 AtomicPointer<T>::operator T*() const { return (T*) ptr_.get(); }
834 
835 
836 template <class T> inline
837 T* AtomicPointer<T>::operator->() { return (T*) ptr_.get(); }
838 
839 
840 template <class T> inline
841 const T* AtomicPointer<T>::operator->() const { return (T*) ptr_.get(); }
842 
843 
844 template <class T> inline
846 { return ptr_ += b*sizeof(T); }
847 
848 
849 template <class T> inline
851 { return ptr_ -= b*sizeof(T); }
852 
853 
854 
855 #define mImplAtomicPointerOperator( func, op, ret ) \
856 template <class T> inline \
857 T* AtomicPointer<T>::func \
858 { \
859  mAtomicPointerType old = (mAtomicPointerType) ptr_.get(); \
860  \
861  while ( !ptr_.setIfValueIs( old, (mAtomicPointerType) (op), &old ) ) \
862  {} \
863  \
864  return ret; \
865 }
866 
867 
868 mImplAtomicPointerOperator( operator++(), old+1, old+1 );
869 mImplAtomicPointerOperator( operator--(), old-1, old-1 );
870 mImplAtomicPointerOperator( operator++(int), old+1, old );
871 mImplAtomicPointerOperator( operator--(int), old-1, old );
872 
873 
874 } //namespace
875 
876 #endif
#define mExpClass(module)
Definition: commondefs.h:160
Atomic(T val=0)
Definition: atomic.h:326
T operator=(T v)
Definition: atomic.h:349
bool setIfValueIs(T curval, T newval, T *actualvalptr)
Definition: atomic.h:398
SpinLock & operator=(const SpinLock &b)
Definition: atomic.h:211
~Atomic()
Definition: atomic.h:337
bool setIfEqual(const T *curptr, T *newptr)
Definition: atomic.h:792
AtomicPointer(const AtomicPointer< T > &)
Definition: atomic.h:178
T * setToNull()
Definition: atomic.h:807
T * exchange(T *newptr)
Definition: atomic.h:800
#define mAtomicPointerType
Definition: atomic.h:134
AtomicPointer< const void > lockingthread_
Definition: atomic.h:219
const void * getStorage() const
Only for debugging.
Definition: atomic.h:426
T operator++()
Definition: atomic.h:371
T operator=(const Atomic< T > &v)
Definition: atomic.h:45
AtomicPointer(T *newptr=0)
Definition: atomic.h:786
T operator--()
Definition: atomic.h:378
interface to threads that should be portable.
Definition: atomic.h:28
T operator+=(T)
Definition: atomic.h:357
int count() const
Definition: atomic.h:226
T operator-=(T)
Definition: atomic.h:364
T * operator+=(int)
Definition: atomic.h:845
Is an alternative to Mutex. It is a lock which causes a thread trying to acquire it to simply wait in...
Definition: atomic.h:200
T * operator-=(int)
Definition: atomic.h:850
bool recursive_
Definition: atomic.h:223
bool atomicSetIfValueIs(volatile int &val, int curval, int newval, int *actualvalptr)
Definition: atomic.h:99
Definition: thread.h:228
T get() const
Definition: atomic.h:342
T exchange(T newval)
Definition: atomic.h:419
Atomic instantiated with a pointer. The class really only handles the casting from a void* to a T*...
Definition: atomic.h:144
Is a lock that allows a thread to have exlusive rights to something.
Definition: thread.h:43
int count_
Definition: atomic.h:222
#define mImplAtomicPointerOperator(func, op, ret)
Definition: atomic.h:855
Atomic< T * > ptr_
Definition: atomic.h:181
Definition: atomic.h:33
#define mClass(module)
Definition: commondefs.h:164
const void * getStorage() const
Only for debugging.
Definition: atomic.h:184
T * operator->()
Definition: atomic.h:837
volatile T val_
Definition: atomic.h:82
AtomicPointer< T > & operator=(T *ptr)
Definition: atomic.h:818

Generated at for the OpendTect seismic interpretation project. Copyright (C): dGB Beheer B. V. 2019