You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							554 lines
						
					
					
						
							21 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							554 lines
						
					
					
						
							21 KiB
						
					
					
				| /* | |
|     Copyright 2005-2013 Intel Corporation.  All Rights Reserved. | |
|  | |
|     This file is part of Threading Building Blocks. | |
|  | |
|     Threading Building Blocks is free software; you can redistribute it | |
|     and/or modify it under the terms of the GNU General Public License | |
|     version 2 as published by the Free Software Foundation. | |
|  | |
|     Threading Building Blocks is distributed in the hope that it will be | |
|     useful, but WITHOUT ANY WARRANTY; without even the implied warranty | |
|     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |
|     GNU General Public License for more details. | |
|  | |
|     You should have received a copy of the GNU General Public License | |
|     along with Threading Building Blocks; if not, write to the Free Software | |
|     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | |
|  | |
|     As a special exception, you may use this file as part of a free software | |
|     library without restriction.  Specifically, if other files instantiate | |
|     templates or use macros or inline functions from this file, or you compile | |
|     this file and link it with other files to produce an executable, this | |
|     file does not by itself cause the resulting executable to be covered by | |
|     the GNU General Public License.  This exception does not however | |
|     invalidate any other reasons why the executable file might be covered by | |
|     the GNU General Public License. | |
| */ | |
| 
 | |
| #ifndef __TBB_atomic_H | |
| #define __TBB_atomic_H | |
|  | |
| #include "tbb_stddef.h" | |
| #include <cstddef> | |
|  | |
| #if _MSC_VER | |
| #define __TBB_LONG_LONG __int64 | |
| #else | |
| #define __TBB_LONG_LONG long long | |
| #endif /* _MSC_VER */ | |
|  | |
| #include "tbb_machine.h" | |
|  | |
| #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) | |
|     // Workaround for overzealous compiler warnings | |
|     #pragma warning (push) | |
|     #pragma warning (disable: 4244 4267) | |
| #endif | |
|  | |
| namespace tbb { | |
| 
 | |
| //! Specifies memory semantics. | |
| enum memory_semantics { | |
|     //! Sequential consistency | |
|     full_fence, | |
|     //! Acquire | |
|     acquire, | |
|     //! Release | |
|     release, | |
|     //! No ordering | |
|     relaxed | |
| }; | |
| 
 | |
| //! @cond INTERNAL | |
| namespace internal { | |
| 
 | |
| #if __TBB_ATTRIBUTE_ALIGNED_PRESENT | |
|     #define __TBB_DECL_ATOMIC_FIELD(t,f,a) t f  __attribute__ ((aligned(a))); | |
| #elif __TBB_DECLSPEC_ALIGN_PRESENT | |
|     #define __TBB_DECL_ATOMIC_FIELD(t,f,a) __declspec(align(a)) t f; | |
| #else | |
|     #error Do not know syntax for forcing alignment. | |
| #endif | |
|  | |
| template<size_t S> | |
| struct atomic_rep;           // Primary template declared, but never defined. | |
|  | |
| template<> | |
| struct atomic_rep<1> {       // Specialization | |
|     typedef int8_t word; | |
| }; | |
| template<> | |
| struct atomic_rep<2> {       // Specialization | |
|     typedef int16_t word; | |
| }; | |
| template<> | |
| struct atomic_rep<4> {       // Specialization | |
| #if _MSC_VER && !_WIN64 | |
|     // Work-around that avoids spurious /Wp64 warnings | |
|     typedef intptr_t word; | |
| #else | |
|     typedef int32_t word; | |
| #endif | |
| }; | |
| #if __TBB_64BIT_ATOMICS | |
| template<> | |
| struct atomic_rep<8> {       // Specialization | |
|     typedef int64_t word; | |
| }; | |
| #endif | |
|  | |
| template<typename value_type, size_t size> | |
| struct aligned_storage; | |
| 
 | |
| //the specializations are needed to please MSVC syntax of __declspec(align()) which accept _literal_ constants only | |
| #if __TBB_ATOMIC_CTORS | |
|     #define ATOMIC_STORAGE_PARTIAL_SPECIALIZATION(S)                  \ | |
|     template<typename value_type>                                     \ | |
|     struct aligned_storage<value_type,S> {                            \ | |
|         __TBB_DECL_ATOMIC_FIELD(value_type,my_value,S)                \ | |
|         aligned_storage() = default ;                                 \ | |
|         constexpr aligned_storage(value_type value):my_value(value){} \ | |
|     };                                                                \ | |
|  | |
| #else | |
|     #define ATOMIC_STORAGE_PARTIAL_SPECIALIZATION(S)                  \ | |
|     template<typename value_type>                                     \ | |
|     struct aligned_storage<value_type,S> {                            \ | |
|         __TBB_DECL_ATOMIC_FIELD(value_type,my_value,S)                \ | |
|     };                                                                \ | |
|  | |
| #endif | |
|  | |
| template<typename value_type> | |
| struct aligned_storage<value_type,1> { | |
|     value_type my_value; | |
| #if __TBB_ATOMIC_CTORS | |
|     aligned_storage() = default ; | |
|     constexpr aligned_storage(value_type value):my_value(value){} | |
| #endif | |
| }; | |
| 
 | |
| ATOMIC_STORAGE_PARTIAL_SPECIALIZATION(2) | |
| ATOMIC_STORAGE_PARTIAL_SPECIALIZATION(4) | |
| #if __TBB_64BIT_ATOMICS | |
| ATOMIC_STORAGE_PARTIAL_SPECIALIZATION(8) | |
| #endif | |
|  | |
| template<size_t Size, memory_semantics M> | |
| struct atomic_traits;        // Primary template declared, but not defined. | |
|  | |
| #define __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(S,M)                                                         \ | |
|     template<> struct atomic_traits<S,M> {                                                               \ | |
|         typedef atomic_rep<S>::word word;                                                                \ | |
|         inline static word compare_and_swap( volatile void* location, word new_value, word comparand ) { \ | |
|             return __TBB_machine_cmpswp##S##M(location,new_value,comparand);                             \ | |
|         }                                                                                                \ | |
|         inline static word fetch_and_add( volatile void* location, word addend ) {                       \ | |
|             return __TBB_machine_fetchadd##S##M(location,addend);                                        \ | |
|         }                                                                                                \ | |
|         inline static word fetch_and_store( volatile void* location, word value ) {                      \ | |
|             return __TBB_machine_fetchstore##S##M(location,value);                                       \ | |
|         }                                                                                                \ | |
|     }; | |
|  | |
| #define __TBB_DECL_ATOMIC_PRIMITIVES(S)                                                                  \ | |
|     template<memory_semantics M>                                                                         \ | |
|     struct atomic_traits<S,M> {                                                                          \ | |
|         typedef atomic_rep<S>::word word;                                                                \ | |
|         inline static word compare_and_swap( volatile void* location, word new_value, word comparand ) { \ | |
|             return __TBB_machine_cmpswp##S(location,new_value,comparand);                                \ | |
|         }                                                                                                \ | |
|         inline static word fetch_and_add( volatile void* location, word addend ) {                       \ | |
|             return __TBB_machine_fetchadd##S(location,addend);                                           \ | |
|         }                                                                                                \ | |
|         inline static word fetch_and_store( volatile void* location, word value ) {                      \ | |
|             return __TBB_machine_fetchstore##S(location,value);                                          \ | |
|         }                                                                                                \ | |
|     }; | |
|  | |
| template<memory_semantics M> | |
| struct atomic_load_store_traits;    // Primary template declaration | |
|  | |
| #define __TBB_DECL_ATOMIC_LOAD_STORE_PRIMITIVES(M)                      \ | |
|     template<> struct atomic_load_store_traits<M> {                     \ | |
|         template <typename T>                                           \ | |
|         inline static T load( const volatile T& location ) {            \ | |
|             return __TBB_load_##M( location );                          \ | |
|         }                                                               \ | |
|         template <typename T>                                           \ | |
|         inline static void store( volatile T& location, T value ) {     \ | |
|             __TBB_store_##M( location, value );                         \ | |
|         }                                                               \ | |
|     } | |
|  | |
| #if __TBB_USE_FENCED_ATOMICS | |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(1,full_fence) | |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(2,full_fence) | |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(4,full_fence) | |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(1,acquire) | |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(2,acquire) | |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(4,acquire) | |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(1,release) | |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(2,release) | |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(4,release) | |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(1,relaxed) | |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(2,relaxed) | |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(4,relaxed) | |
| #if __TBB_64BIT_ATOMICS | |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(8,full_fence) | |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(8,acquire) | |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(8,release) | |
| __TBB_DECL_FENCED_ATOMIC_PRIMITIVES(8,relaxed) | |
| #endif | |
| #else /* !__TBB_USE_FENCED_ATOMICS */ | |
| __TBB_DECL_ATOMIC_PRIMITIVES(1) | |
| __TBB_DECL_ATOMIC_PRIMITIVES(2) | |
| __TBB_DECL_ATOMIC_PRIMITIVES(4) | |
| #if __TBB_64BIT_ATOMICS | |
| __TBB_DECL_ATOMIC_PRIMITIVES(8) | |
| #endif | |
| #endif /* !__TBB_USE_FENCED_ATOMICS */ | |
|  | |
| __TBB_DECL_ATOMIC_LOAD_STORE_PRIMITIVES(full_fence); | |
| __TBB_DECL_ATOMIC_LOAD_STORE_PRIMITIVES(acquire); | |
| __TBB_DECL_ATOMIC_LOAD_STORE_PRIMITIVES(release); | |
| __TBB_DECL_ATOMIC_LOAD_STORE_PRIMITIVES(relaxed); | |
| 
 | |
| //! Additive inverse of 1 for type T. | |
| /** Various compilers issue various warnings if -1 is used with various integer types. | |
|     The baroque expression below avoids all the warnings (we hope). */ | |
| #define __TBB_MINUS_ONE(T) (T(T(0)-T(1))) | |
|  | |
| //! Base class that provides basic functionality for atomic<T> without fetch_and_add. | |
| /** Works for any type T that has the same size as an integral type, has a trivial constructor/destructor, | |
|     and can be copied/compared by memcpy/memcmp. */ | |
| template<typename T> | |
| struct atomic_impl { | |
| protected: | |
|     aligned_storage<T,sizeof(T)> my_storage; | |
| private: | |
|     //TODO: rechecks on recent versions of gcc if union is still the _only_ way to do a conversion without warnings | |
|     //! Union type used to convert type T to underlying integral type. | |
|     template<typename value_type> | |
|     union converter { | |
|         typedef typename atomic_rep<sizeof(value_type)>::word bits_type; | |
|         converter(){} | |
|         converter(value_type a_value) : value(a_value) {} | |
|         value_type value; | |
|         bits_type bits; | |
|     }; | |
| 
 | |
|     template<typename value_t> | |
|     union ptr_converter;            //Primary template declared, but never defined. | |
|  | |
|     template<typename value_t> | |
|     union ptr_converter<value_t *> { | |
|         typedef typename atomic_rep<sizeof(value_t)>::word * bits_ptr_type; | |
|         ptr_converter(){} | |
|         ptr_converter(value_t* a_value) : value(a_value) {} | |
|         value_t* value; | |
|         bits_ptr_type bits; | |
|     }; | |
| 
 | |
|     template<typename value_t> | |
|     static typename converter<value_t>::bits_type to_bits(value_t value){ | |
|         return converter<value_t>(value).bits; | |
|     } | |
|     template<typename value_t> | |
|     static value_t to_value(typename converter<value_t>::bits_type bits){ | |
|         converter<value_t> u; | |
|         u.bits = bits; | |
|         return u.value; | |
|     } | |
| 
 | |
|     //separate function is needed as it is impossible to distinguish (and thus overload to_bits) | |
|     //whether the pointer passed in is a pointer to atomic location or a value of that location | |
|     template<typename value_t> | |
|     static typename ptr_converter<value_t*>::bits_ptr_type to_bits_ptr(value_t* value){ | |
|         //TODO: try to use cast to void* and second cast to required pointer type; | |
|         //Once (and if) union converter goes away - check if strict aliasing warning | |
|         //suppression is still needed once. | |
|         //TODO: this #ifdef is temporary workaround, as union conversion seems to fail | |
|         //on suncc for 64 bit types for 32 bit target | |
|         #if !__SUNPRO_CC | |
|             return ptr_converter<value_t*>(value).bits; | |
|         #else | |
|             return typename ptr_converter<value_t*>::bits_ptr_type (value); | |
|         #endif | |
|     } | |
| 
 | |
| public: | |
|     typedef T value_type; | |
| 
 | |
| #if __TBB_ATOMIC_CTORS | |
|     atomic_impl() = default ; | |
|     constexpr atomic_impl(value_type value):my_storage(value){} | |
| #endif | |
|     template<memory_semantics M> | |
|     value_type fetch_and_store( value_type value ) { | |
|           return to_value<value_type>(internal::atomic_traits<sizeof(value_type),M>::fetch_and_store(&my_storage.my_value,to_bits(value))); | |
|     } | |
| 
 | |
|     value_type fetch_and_store( value_type value ) { | |
|         return fetch_and_store<full_fence>(value); | |
|     } | |
| 
 | |
|     template<memory_semantics M> | |
|     value_type compare_and_swap( value_type value, value_type comparand ) { | |
|         return to_value<value_type>(internal::atomic_traits<sizeof(value_type),M>::compare_and_swap(&my_storage.my_value,to_bits(value),to_bits(comparand))); | |
|     } | |
| 
 | |
|     value_type compare_and_swap( value_type value, value_type comparand ) { | |
|         return compare_and_swap<full_fence>(value,comparand); | |
|     } | |
| 
 | |
|     operator value_type() const volatile {                // volatile qualifier here for backwards compatibility | |
|         return  to_value<value_type>(__TBB_load_with_acquire(*to_bits_ptr(&my_storage.my_value))); | |
|     } | |
| 
 | |
|     template<memory_semantics M> | |
|     value_type load () const { | |
|         return to_value<value_type>(internal::atomic_load_store_traits<M>::load(*to_bits_ptr(&my_storage.my_value))); | |
|     } | |
| 
 | |
|     value_type load () const { | |
|         return load<acquire>(); | |
|     } | |
| 
 | |
|     template<memory_semantics M> | |
|     void store ( value_type value ) { | |
|         internal::atomic_load_store_traits<M>::store( *to_bits_ptr(&my_storage.my_value), to_bits(value)); | |
|     } | |
| 
 | |
|     void store ( value_type value ) { | |
|         store<release>( value ); | |
|     } | |
| 
 | |
| protected: | |
|     value_type store_with_release( value_type rhs ) { | |
|         __TBB_store_with_release(*to_bits_ptr(&my_storage.my_value),to_bits(rhs)); | |
|         return rhs; | |
|     } | |
| }; | |
| 
 | |
| //! Base class that provides basic functionality for atomic<T> with fetch_and_add. | |
| /** I is the underlying type. | |
|     D is the difference type. | |
|     StepType should be char if I is an integral type, and T if I is a T*. */ | |
| template<typename I, typename D, typename StepType> | |
| struct atomic_impl_with_arithmetic: atomic_impl<I> { | |
| public: | |
|     typedef I value_type; | |
| #if    __TBB_ATOMIC_CTORS | |
|     atomic_impl_with_arithmetic() = default ; | |
|     constexpr atomic_impl_with_arithmetic(value_type value): atomic_impl<I>(value){} | |
| #endif | |
|     template<memory_semantics M> | |
|     value_type fetch_and_add( D addend ) { | |
|         return value_type(internal::atomic_traits<sizeof(value_type),M>::fetch_and_add( &this->my_storage.my_value, addend*sizeof(StepType) )); | |
|     } | |
| 
 | |
|     value_type fetch_and_add( D addend ) { | |
|         return fetch_and_add<full_fence>(addend); | |
|     } | |
| 
 | |
|     template<memory_semantics M> | |
|     value_type fetch_and_increment() { | |
|         return fetch_and_add<M>(1); | |
|     } | |
| 
 | |
|     value_type fetch_and_increment() { | |
|         return fetch_and_add(1); | |
|     } | |
| 
 | |
|     template<memory_semantics M> | |
|     value_type fetch_and_decrement() { | |
|         return fetch_and_add<M>(__TBB_MINUS_ONE(D)); | |
|     } | |
| 
 | |
|     value_type fetch_and_decrement() { | |
|         return fetch_and_add(__TBB_MINUS_ONE(D)); | |
|     } | |
| 
 | |
| public: | |
|     value_type operator+=( D value ) { | |
|         return fetch_and_add(value)+value; | |
|     } | |
| 
 | |
|     value_type operator-=( D value ) { | |
|         // Additive inverse of value computed using binary minus, | |
|         // instead of unary minus, for sake of avoiding compiler warnings. | |
|         return operator+=(D(0)-value); | |
|     } | |
| 
 | |
|     value_type operator++() { | |
|         return fetch_and_add(1)+1; | |
|     } | |
| 
 | |
|     value_type operator--() { | |
|         return fetch_and_add(__TBB_MINUS_ONE(D))-1; | |
|     } | |
| 
 | |
|     value_type operator++(int) { | |
|         return fetch_and_add(1); | |
|     } | |
| 
 | |
|     value_type operator--(int) { | |
|         return fetch_and_add(__TBB_MINUS_ONE(D)); | |
|     } | |
| }; | |
| 
 | |
| } /* Internal */ | |
| //! @endcond | |
|  | |
| //! Primary template for atomic. | |
| /** See the Reference for details. | |
|     @ingroup synchronization */ | |
| template<typename T> | |
| struct atomic: internal::atomic_impl<T> { | |
| #if __TBB_ATOMIC_CTORS | |
|     atomic() = default; | |
|     constexpr atomic(T arg): internal::atomic_impl<T>(arg) {} | |
| #endif | |
|     T operator=( T rhs ) { | |
|         // "this" required here in strict ISO C++ because store_with_release is a dependent name | |
|         return this->store_with_release(rhs); | |
|     } | |
|     atomic<T>& operator=( const atomic<T>& rhs ) {this->store_with_release(rhs); return *this;} | |
| }; | |
| 
 | |
| #if __TBB_ATOMIC_CTORS | |
|     #define __TBB_DECL_ATOMIC(T)                                                                    \ | |
|         template<> struct atomic<T>: internal::atomic_impl_with_arithmetic<T,T,char> {              \ | |
|             atomic() = default;                                                                             \ | |
|             constexpr atomic(T arg): internal::atomic_impl_with_arithmetic<T,T,char>(arg) {}        \ | |
|                                                                                                     \ | |
|             T operator=( T rhs ) {return store_with_release(rhs);}                                  \ | |
|             atomic<T>& operator=( const atomic<T>& rhs ) {store_with_release(rhs); return *this;}   \ | |
|         }; | |
| #else | |
|     #define __TBB_DECL_ATOMIC(T)                                                                    \ | |
|         template<> struct atomic<T>: internal::atomic_impl_with_arithmetic<T,T,char> {              \ | |
|             T operator=( T rhs ) {return store_with_release(rhs);}                                  \ | |
|             atomic<T>& operator=( const atomic<T>& rhs ) {store_with_release(rhs); return *this;}   \ | |
|         }; | |
| #endif | |
|  | |
| #if __TBB_64BIT_ATOMICS | |
| //TODO: consider adding non-default (and atomic) copy constructor for 32bit platform | |
| __TBB_DECL_ATOMIC(__TBB_LONG_LONG) | |
| __TBB_DECL_ATOMIC(unsigned __TBB_LONG_LONG) | |
| #else | |
| // test_atomic will verify that sizeof(long long)==8 | |
| #endif | |
| __TBB_DECL_ATOMIC(long) | |
| __TBB_DECL_ATOMIC(unsigned long) | |
| 
 | |
| #if _MSC_VER && !_WIN64 | |
| #if __TBB_ATOMIC_CTORS | |
| /* Special version of __TBB_DECL_ATOMIC that avoids gratuitous warnings from cl /Wp64 option. | |
|    It is identical to __TBB_DECL_ATOMIC(unsigned) except that it replaces operator=(T) | |
|    with an operator=(U) that explicitly converts the U to a T.  Types T and U should be | |
|    type synonyms on the platform.  Type U should be the wider variant of T from the | |
|    perspective of /Wp64. */ | |
| #define __TBB_DECL_ATOMIC_ALT(T,U) \ | |
|     template<> struct atomic<T>: internal::atomic_impl_with_arithmetic<T,T,char> {             \ | |
|         atomic() = default ;                                                                            \ | |
|         constexpr atomic(T arg): internal::atomic_impl_with_arithmetic<T,T,char>(arg) {}       \ | |
|         T operator=( U rhs ) {return store_with_release(T(rhs));}                              \ | |
|         atomic<T>& operator=( const atomic<T>& rhs ) {store_with_release(rhs); return *this;}  \ | |
|     }; | |
| #else | |
| #define __TBB_DECL_ATOMIC_ALT(T,U) \ | |
|     template<> struct atomic<T>: internal::atomic_impl_with_arithmetic<T,T,char> {             \ | |
|         T operator=( U rhs ) {return store_with_release(T(rhs));}                              \ | |
|         atomic<T>& operator=( const atomic<T>& rhs ) {store_with_release(rhs); return *this;}  \ | |
|     }; | |
| #endif | |
| __TBB_DECL_ATOMIC_ALT(unsigned,size_t) | |
| __TBB_DECL_ATOMIC_ALT(int,ptrdiff_t) | |
| #else | |
| __TBB_DECL_ATOMIC(unsigned) | |
| __TBB_DECL_ATOMIC(int) | |
| #endif /* _MSC_VER && !_WIN64 */ | |
|  | |
| __TBB_DECL_ATOMIC(unsigned short) | |
| __TBB_DECL_ATOMIC(short) | |
| __TBB_DECL_ATOMIC(char) | |
| __TBB_DECL_ATOMIC(signed char) | |
| __TBB_DECL_ATOMIC(unsigned char) | |
| 
 | |
| #if !_MSC_VER || defined(_NATIVE_WCHAR_T_DEFINED) | |
| __TBB_DECL_ATOMIC(wchar_t) | |
| #endif /* _MSC_VER||!defined(_NATIVE_WCHAR_T_DEFINED) */ | |
|  | |
| //! Specialization for atomic<T*> with arithmetic and operator->. | |
| template<typename T> struct atomic<T*>: internal::atomic_impl_with_arithmetic<T*,ptrdiff_t,T> { | |
| #if __TBB_ATOMIC_CTORS | |
|     atomic() = default ; | |
|     constexpr atomic(T* arg): internal::atomic_impl_with_arithmetic<T*,ptrdiff_t,T>(arg) {} | |
| #endif | |
|     T* operator=( T* rhs ) { | |
|         // "this" required here in strict ISO C++ because store_with_release is a dependent name | |
|         return this->store_with_release(rhs); | |
|     } | |
|     atomic<T*>& operator=( const atomic<T*>& rhs ) { | |
|         this->store_with_release(rhs); return *this; | |
|     } | |
|     T* operator->() const { | |
|         return (*this); | |
|     } | |
| }; | |
| 
 | |
| //! Specialization for atomic<void*>, for sake of not allowing arithmetic or operator->. | |
| template<> struct atomic<void*>: internal::atomic_impl<void*> { | |
| #if __TBB_ATOMIC_CTORS | |
|     atomic() = default ; | |
|     constexpr atomic(void* arg): internal::atomic_impl<void*>(arg) {} | |
| #endif | |
|     void* operator=( void* rhs ) { | |
|         // "this" required here in strict ISO C++ because store_with_release is a dependent name | |
|         return this->store_with_release(rhs); | |
|     } | |
|     atomic<void*>& operator=( const atomic<void*>& rhs ) { | |
|         this->store_with_release(rhs); return *this; | |
|     } | |
| }; | |
| 
 | |
| // Helpers to workaround ugly syntax of calling template member function of a | |
| // template class with template argument dependent on template parameters. | |
|  | |
| template <memory_semantics M, typename T> | |
| T load ( const atomic<T>& a ) { return a.template load<M>(); } | |
| 
 | |
| template <memory_semantics M, typename T> | |
| void store ( atomic<T>& a, T value ) { return a.template store<M>(value); } | |
| 
 | |
| namespace interface6{ | |
| //! Make an atomic for use in an initialization (list), as an alternative to zero-initializaton or normal assignment. | |
| template<typename T> | |
| atomic<T> make_atomic(T t) { | |
|     atomic<T> a; | |
|     store<relaxed>(a,t); | |
|     return a; | |
| } | |
| } | |
| using interface6::make_atomic; | |
| 
 | |
| namespace internal { | |
| 
 | |
| // only to aid in the gradual conversion of ordinary variables to proper atomics | |
| template<typename T> | |
| inline atomic<T>& as_atomic( T& t ) { | |
|     return (atomic<T>&)t; | |
| } | |
| } // namespace tbb::internal | |
|  | |
| } // namespace tbb | |
|  | |
| #if _MSC_VER && !__INTEL_COMPILER | |
|     #pragma warning (pop) | |
| #endif // warnings 4244, 4267 are back | |
|  | |
| #endif /* __TBB_atomic_H */
 |