Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 how to identify atomic type at compile time (via mtl or defines)?

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).

like image 275
myWallJSON Avatar asked Dec 01 '22 20:12

myWallJSON


2 Answers

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.

like image 150
JoergB Avatar answered Jan 05 '23 17:01

JoergB


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.

like image 25
Anthony Williams Avatar answered Jan 05 '23 19:01

Anthony Williams