1146. "lockfree" does not say enough

Section: 32.5 [atomics.lockfree] Status: Resolved Submitter: Jeffrey Yasskin Opened: 2009-06-16 Last modified: 2016-02-25

Priority: Not Prioritized

View all other issues in [atomics.lockfree].

View all issues with Resolved status.

Discussion:

Addresses US 88

The "lockfree" facilities do not tell the programmer enough.

There are 2 problems here. First, at least on x86, it's less important to me whether some integral types are lock free than what is the largest type I can pass to atomic and have it be lock-free. For example, if long longs are not lock-free, ATOMIC_INTEGRAL_LOCK_FREE is probably 1, but I'd still be interested in knowing whether longs are always lock-free. Or if long longs at any address are lock-free, I'd expect ATOMIC_INTEGRAL_LOCK_FREE to be 2, but I may actually care whether I have access to the cmpxchg16b instruction. None of the support here helps with that question. (There are really 2 related questions here: what alignment requirements are there for lock-free access; and what processor is the program actually running on, as opposed to what it was compiled for?)

Second, having atomic_is_lock_free only apply to individual objects is pretty useless (except, as Lawrence Crowl points out, for throwing an exception when an object is unexpectedly not lock-free). I'm likely to want to use its result to decide what algorithm to use, and that algorithm is probably going to allocate new memory containing atomic objects and then try to act on them. If I can't predict the lock-freedom of the new object by checking the lock-freedom of an existing object, I may discover after starting the algorithm that I can't continue.

[ 2009-06-16 Jeffrey Yasskin adds: ]

To solve the first problem, I think 2 macros would help: MAX_POSSIBLE_LOCK_FREE_SIZE and MAX_GUARANTEED_LOCK_FREE_SIZE, which expand to the maximum value of sizeof(T) for which atomic may (or will, respectively) use lock-free operations. Lawrence points out that this "relies heavily on implementations using word-size compare-swap on sub-word-size types, which in turn requires address modulation." He expects that to be the end state anyway, so it doesn't bother him much.

To solve the second, I think one could specify that equally aligned objects of the same type will return the same value from atomic_is_lock_free(). I don't know how to specify "equal alignment". Lawrence suggests an additional function, atomic_is_always_lock_free().

[ 2009-10-22 Benjamin Kosnik: ]

In the evolution discussion of N2925, "More Collected Issues with Atomics," there is an action item with respect to LWG 1146, US 88

This is stated in the paper as:

Relatedly, Mike Sperts will create an issue to propose adding a traits mechanism to check the compile-time properties through a template mechanism rather than macros

Here is my attempt to do this. I don't believe that a separate trait is necessary for this, and that instead atomic_integral::is_lock_free can be re-purposed with minimal work as follows.

[ Howard: Put Benjamin's wording in the proposed wording section. ]

[ 2009-10-22 Alberto Ganesh Barbati: ]

Just a thought... wouldn't it be better to use a scoped enum instead of plain integers? For example:

enum class is_lock_free
{
    never = 0, sometimes = 1, always = 2;
};

if compatibility with C is deemed important, we could use an unscoped enum with suitably chosen names. It would still be more descriptive than 0, 1 and 2.

Previous resolution [SUPERSEDED]:

Header <cstdatomic> synopsis [atomics.synopsis]

Edit as follows:

namespace std {
...
// 29.4, lock-free property
#define ATOMIC_INTEGRAL_LOCK_FREE unspecified
#define ATOMIC_CHAR_LOCK_FREE unspecified
#define ATOMIC_CHAR16_T_LOCK_FREE unspecified
#define ATOMIC_CHAR32_T_LOCK_FREE unspecified
#define ATOMIC_WCHAR_T_LOCK_FREE unspecified
#define ATOMIC_SHORT_LOCK_FREE unspecified
#define ATOMIC_INT_LOCK_FREE unspecified
#define ATOMIC_LONG_LOCK_FREE unspecified
#define ATOMIC_LLONG_LOCK_FREE unspecified
#define ATOMIC_ADDRESS_LOCK_FREE unspecified

Lock-free Property 32.5 [atomics.lockfree]

Edit the synopsis as follows.

namespace std {
   #define ATOMIC_INTEGRAL_LOCK_FREE unspecified
   #define ATOMIC_CHAR_LOCK_FREE unspecified
   #define ATOMIC_CHAR16_T_LOCK_FREE unspecified
   #define ATOMIC_CHAR32_T_LOCK_FREE unspecified
   #define ATOMIC_WCHAR_T_LOCK_FREE unspecified
   #define ATOMIC_SHORT_LOCK_FREE unspecified
   #define ATOMIC_INT_LOCK_FREE unspecified
   #define ATOMIC_LONG_LOCK_FREE unspecified
   #define ATOMIC_LLONG_LOCK_FREE unspecified
   #define ATOMIC_ADDRESS_LOCK_FREE unspecified
}

Edit paragraph 1 as follows.

The ATOMIC_...._LOCK_FREE macros ATOMIC_INTEGRAL_LOCK_FREE and ATOMIC_ADDRESS_LOCK_FREE indicate the general lock-free property of integral and address atomic the corresponding atomic integral types, with the signed and unsigned variants grouped together. The properties also apply to the corresponding specializations of the atomic template. A value of 0 indicates that the types are never lock-free. A value of 1 indicates that the types are sometimes lock-free. A value of 2 indicates that the types are always lock-free.

Operations on Atomic Types 32.6.1 [atomics.types.operations]

Edit as follows.

void static constexpr bool A::is_lock_free() const volatile;

Returns: True if the object's types's operations are lock-free, false otherwise. [Note: In the same way that <limits> std::numeric_limits<short>::max() is related to <limits.h> __LONG_LONG_MAX__, <atomic> std::atomic_short::is_lock_free is related to <stdatomic.h> and ATOMIC_SHORT_LOCK_FREEend note]

[ 2009-10 Santa Cruz: ]

NAD EditorialResolved. Solved by N2992.

Proposed resolution:

Resolved by N2992.