Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
120 lines (91 sloc) 4.44 KB

P0152R0 constexpr atomic<T>::is_always_lock_free

Author: Olivier Giroux
Contact: ogiroux@nvidia.com
Author: JF Bastien
Contact: jfb@google.com
Author: Jeff Snyder
Contact: jeff-isocpp@caffeinated.me.uk
Date: 2015-10-21
Previous:http://wg21.link/N4509
URL:https://github.com/jfbastien/papers/blob/master/source/P0152R0.rst
Source:https://github.com/jfbastien/papers/blob/master/source/P0152.cc

The current design for std::atomic<T> affords implementations the critical freedom to revert to critical sections when hardware support for atomic operations does not meet the size or semantic requirements for the associated type T. This:

  • Preserves C++ support on aging hardware.
  • Supports developers who don't target a specific architecture e.g. with the -march=xxx flag.
  • Improves the portability of abstract representations for C++ programs, e.g. when compiling C++ code to execute portably within a web browser.

The Standard also ensures that developers can be informed of the implementation's lock-freedom guarantees, by using the is_lock_free() member and free-functions. This is important because programmers may want to select algorithm implementations, or even select algorithms, based on this knowledge. Developers are equally likely to do so for correctness and performance reasons.

The software design shipped in C++11 and C++14 is, however, somewhat sandbagged.

There is poor support for static determination of lock-freedom guarantees.

At the present time the Standard has limited support in this domain: the ATOMIC_..._LOCK_FREE macros that return 2, 1 or 0 if the corresponding atomic type is always lock-free, sometimes lock-free or never lock-free, respectively. These macros are little more than a consolation prize because they do not work with an arbitrary type T (as the C++ native std::atomic<T> library intends) and they leave adaptation for generic programming entirely up to the developer.

This leads to the present, counter-intuitive state of the art whereby non-traditional uses of C++ have better support than high-performance computing. We aim to make the smallest possible change that improves the situation for HPC while leaving all other uses untouched.

We propose a static constexpr complement of is_lock_free() that is suitable for use with SFINAE and static_assert.

Proposed addition

Under 29.5 Atomic types [atomics.types.generic]:

namespace std {
  template <class T> struct atomic {
    static constexpr bool is_always_lock_free = implementation-defined;
    // Omitting all other members for brevity.
  };
  template <> struct atomic<integral> {
    static constexpr bool is_always_lock_free = implementation-defined;
    // Omitting all other members for brevity.
  };
  template <class T> struct atomic<T*> {
    static constexpr bool is_always_lock_free = implementation-defined;
    // Omitting all other members for brevity.
  };
}

Under 29.6.5 Requirements for operations on atomic types [atomics.types.operations.req], between paragraphs 6 and 7:

static constexpr bool is_always_lock_free = implementation-defined;

The static data member is_always_lock_free is true if the atomic type's operations are always lock-free, and false otherwise. The value of is_always_lock_free shall be consistent with the value of the corresponding ATOMIC_..._LOCK_FREE macro, if defined.

Under 29.6.5 Requirements for operations on atomic types [atomics.types.operations.req], in paragraph 7:

The return value of the is_lock_free member function shall be consistent with the value of is_always_lock_free for the same type.

[Example: The following should never fail

if (atomic<T>::is_always_lock_free)
  assert(atomic<T>().is_lock_free());

end example]

The __cpp_lib_atomic_is_always_lock_free feature test macro should be added.

Additional material

We did not provide the atomic_is_always_lock_free C-style free functions (which the is_lock_free functions have) because these require a pointer. This makes the free functions significantly less useful as compile-time constexpr.

We show a sample implementation:

.. literalinclude:: P0152.cc
   :language: c++
   :lines: 4-48