C11 Atomics in Visual Studio 2022 version 17.5 Preview 2

Charlie Barto

MSVC gained support for C11 and C17 back in Visual Studio 2019 version 16.8, but at the time we left out support for some C11 optional features such as atomics, threads, and complex numbers. We are happy to announce that in Visual Studio 2022 17.5 Preview 2 we are adding an experimental implementation of C11 atomics.

Atomics are available in Visual Studio 2022 version 17.5 Preview 2 with the /experimental:c11atomics flag, in /std:c11 mode or later. At the moment only lock-free atomics are supported, but in an upcoming release we will extend this support to include locking atomics as well. Atomics of all the usual built-in C types are lock-free, including long long on 32-bit x86. We will continue to define the __STDC_NO_ATOMICS__ macro even under /experimental:c11atomics until locking atomics are implemented.

Atomics

C11 atomics add the <stdatomic.h> library header, the _Atomic(T) type specifier, and the _Atomic “qualifier” (which is more of a shortcut for _Atomic(T) than a real qualifier).

_Atomic(T) or _Atomic can be used to declare an atomic:

_Atomic(int) a; // using the specifier
_Atomic int a; // using the qualifier

This works for structs as well, for example:

struct cat {
   int a;
};

_Atomic struct cat furball;
_Atomic(struct cat) fuzzball;

When you’re declaring a struct and defining a variable of the same type you can put _Atomic(T) and _Atomic in a number of places:

_Atomic(struct {
    int a;
}) meow;

_Atomic(struct cat {
    int a;
}) furball;

_Atomic struct {
    int a;
} purr;

struct {
    int a;
} _Atomic purr1;

_Atomic(struct {
    int a;
}) _Atomic purr2;

_Atomic struct {
    int a;
} _Atomic purr3;

Notice that unlike the _Atomic(T) type specifier you can repeat the _Atomic qualifier as many times as you like, just like other type-qualifiers. The _Atomic qualifier is particularly useful when declaring structs or variables of structure types because it doesn’t require parentheses. It can also be useful in macros or typedefs because it can be repeated any number of times. In other respects it is identical to the type specifier.

Normal C assignment and compound assignment expressions are atomic on atomic types, and the loads and stores involved are done with sequentially consistent memory ordering. Note that unlike C++’s std::atomic the /=, %=, and *= operators are provided, and are atomic. The atomic_load_explicit and atomic_store_explicit library functions allow you to specify a memory order for loads and stores explicitly. Normal C initializers also work on atomic objects, and are not atomic. atomic_init can be used to explicitly initialize an atomic, or to later store to the atomic non-atomically.

The library functions above are provided by <stdatomic.h>, along with the remaining “usual” atomic operations and types. Notice that we are not providing the  ATOMIC_VAR_INIT macro. This macro was deprecated in C17 and removed in C23, and it’s a bit of a trap for the unaware. If the lack of this macro causes problems in your code please let us know.

C++ <atomic> compatibility

The Microsoft C++ standard library has implemented P0943R6: Support C atomics in C++ since Visual Studio 2022 17.1, and our C11 atomics implementation has the same ABI as the STL’s C++ atomics. You can share headers that use atomics between C and C++ code and any atomic operations will be correctly ordered with respect to one another. If you do share headers be sure to limit yourself to the subset of syntax that’s valid in both C and C++; no _Atomic qualifier, no calling member functions on _Atomic(T) types, no using atomic /= expressions, etc. Because this level of compatibility requires C11 atomics to use the exact same ABI as C++ atomics they also inherit some of the limitations of our C++ atomics, namely:

  1. Our atomics are only lock-free for objects with sizes <= 8 and exactly equal to a power of two. Other implementations allow lock-free operations on non-power of two objects <= 16.
  2. Our locking atomics will have the lock stored inside the atomic object, meaning locking atomic objects are bigger than their non-atomic counterparts, and you can’t cast a pointer to a non-atomic object to a pointer to its atomic equivalent. On the other hand it means you can share locking atomics between processes (using shared memory segments) and get correct synchronization.

Codegen for C11 atomics should be almost exactly equivalent to codegen for C++ atomics in release mode, as basic operations are implemented essentially identically. An exception to this is when using C11 atomics without including the stdatomic.h header, like so:

int main(void) {
    _Atomic(int) v = 0;
    v += 3;
    return v;
}

This will generate code containing a call instruction to a support routine implementing atomic increment, even in release mode. Including <stdatomic.h>will allow the code to be inlined, as with C++. Code for the library routines is inside the vcruntime.lib import library, and there’s no additional runtime components to distribute. C11 atomics should work fine on all the platforms supported by the Visual C++ Runtime, which are currently Windows 7 and newer.

Threads

We are working on supporting <threads.h> in an upcoming Visual Studio release. Unlike atomics our implementation of threads will not have the same ABI as C++ threads, although it will likely be possible to include <threads.h> from C++ for interoperability. Stay tuned for updates on this feature in calendar year 2023.

Try them out!

Once you’ve installed Visual Studio 2022 17.5 Preview 2 you can try out C11 atomics by adding /experimental:c11atomics and /std:c11 or /std:c17 to your compile options. Note that we still define __STDC_NO_ATOMICS__ so if your build system is testing for that you will need to add a special case or change to checking if compiling a translation unit including <stdatomic.h> succeeds.

Send us your feedback

If you have any thoughts on this feature, or other ideas on how to improve our tools you can leave a comment below. Additionally you can contact us via email at visualcpp@microsoft.com or report any bugs you encounter using developer community.

0 comments

Discussion is closed.

Feedback usabilla icon