This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Resolved status.

### 1146. "lockfree" does not say enough

Section: 31.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 long`s 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 31.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 31.8.2 [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_FREE` — end note]

[ 2009-10 Santa Cruz: ]

> NAD Editorial Resolved. Solved by N2992.

Proposed resolution:

Resolved by N2992.