4

I wonder if it is possible to determine if a given type is atomic (meaning you can perform operations on it without mutex, not putting yourself in danger).

I wonder if there is some atomic(type) define that would determine if type is atomic. In order to create something like DEFINE( (int)(do) ); that would create pseudocode like:

   int _do;

#if !atomic(int)
    mutex do_mutex;
#endif   

   void set_do(int do)
   {
#if atomic(int)
       _do = do;
#else
       lock(do_mutex);
       _do = do;
#endif
   }

So is there any way to check on define/mtl level if type is atomic (using boost if needed).

Red XIII
  • 5,771
  • 4
  • 28
  • 29
myWallJSON
  • 9,110
  • 22
  • 78
  • 149
  • 12
    Couldn't you just use `std::atomic` and let your implementation decide if it's neccessary to wrap it in a mutex (or use some other kind of atomic synchronization more efficient than throwing a mutex at it). – Christian Rau Jan 31 '13 at 14:26
  • 1
    What is the definition of *atomic* that you are interested in? `int` will never be an atomic type, but you might be wondering about lesser guarantees (loads/stores to an `int` are atomic in some architectures...) – David Rodríguez - dribeas Jan 31 '13 at 15:06

2 Answers2

10

You can't do anything like this at preprocessing time, because that determination requires semantic information about types and their names, which are not available during preprocessing.

A templated is_atomic<T> type trait would have to be provided by the implementation, but isn't available even in C++11. It utility would be very limited, because on platforms that support threads at all, it is rather unusual to have types that are atomic by themselves.

Additionally it may not even be possible to determine this from type alone, as some types have different atomicity properties depending on their memory alignment (without making the alignment requirements for atomicity mandatory for the type).

Instead you should use the implementation provided std::atomic<T>, which ought to provide the most efficient implementation for atomic operations (with given memory constraints) available on a given platform.

By using platform-specific memory fence or atomic access instructions such implementations may be able to provide lock-free atomic types even if the underlying memory model provides atomicity for no 'naked' native type.

You can use std::atomic<T>::is_lockfree() to determine whether such an implementation needs to use locks under the hood.

JoergB
  • 4,383
  • 21
  • 19
  • Well, a templated `is_atomic` is _kind of_ provided, in that all descendants of `atomic` have a member function and there exists a free function template `template bool atomic_is_lock_free(const atomic<_ITp>* __a)`. You can use [SFINAE](http://stackoverflow.com/q/257288/572743) for that matter to determine what kind of "thing" a certain given something is. Though @ChristianRau is correct in his above comment... why do that when you can just use a proper atomic type. – Damon Jan 31 '13 at 15:10
8

The <atomic> header provides ATOMIC_INT_LOCK_FREE and friends, for all the various sizes of built-in type. These are preprocessor macros, and are defined to 0 if the atomic variant of the type is never lock free, 1 if it is sometimes lock free (e.g. if the target system supports it), and 2 if it is always lock free. e.g. if std::atomic<int> is always lock free, but std::atomic<long long> is only sometimes, then ATOMIC_INT_LOCK_FREE will be 2, and ATOMIC_LLONG_LOCK_FREE will be 1. Pointer types are covered by ATOMIC_POINTER_LOCK_FREE.

You could use these macros to decide to use a plain int and a mutex when std::atomic<int> was not lock-free, but in most circumstances you are better off just writing std::atomic<int> and letting the compiler handle it.

Anthony Williams
  • 66,628
  • 14
  • 133
  • 155