June 12th, 2025
0 reactions

Why does Windows even have Interlocked functions when we have std::atomic?

Windows provides a family of functions for performing atomic operations. They have the word Interlocked in their name. But why do these functions even exist when we have std::atomic?

This is similar to asking why they didn’t use the Space Shuttle to rescue the Apollo 13 astronauts. You have the history wrong.

Multithreading and atomic operations were not added to the C and C++ languages until C11 and C++11 (respectively), but Windows was doing multithreading since Windows NT 3.1, which released in 1993. Compilers of that era typically did not include intrinsics for atomic operations, so if you needed to do things atomically, you had to call to an outside function.

The Windows Interlocked functions were those outside functions. Originally, the only operations were to increment, decrement, or exchange a 4-byte value. (And the increment and decrement operations didn’t even tell you the result of the increment/decrement, only the sign.) Gradually, other operations were added, and the size of the operated-on value was expanded to include pointer-sized values.

In the meantime, compilers realized that maybe they should add intrinsics for atomic operations, and the C and C++ standards committees realized that atomic operations would be a nice thing to standardize, so they added _Atomic and std::atomic.

So which one should you use?

If you are coding in C or C++, you may as well use the language built-in operations. Nowadays, the compiler can inline the atomic operations, rather than taking the expense of a function call. And they also can optimize around them, or not optimize around them, which is probably even more important.

So why do the Interlocked functions still exist?

The implementations of the Interlocked functions are typically quite small, so leaving them around doesn’t incur much of a cost. And they are still necessary if you want to perform atomic operations from languages that don’t have built-in atomics.

Bonus chatter: Nowadays, the interlocked functions are typically defined for C and C++ consumers in terms of compiler intrinsics, so at the end of the day, it really doesn’t matter. They all end up turning into compiler intrinsics if you are coding in C and C++.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

7 comments

Discussion is closed. Login to edit/delete existing comments.

  • Georg Rottensteiner

    Errmm, if you removed them, what is C/C++ going to call behind the std::atomic?
    Unless I’m seeing wrong it’s not as if they could implement atomic without OS specific calls anyway.

    At least in my VS install std::atomic is using InterlockedCompareExchange.

    • ‪ ‪

      Not correct.
      Using _InterlockedCompareExchange intrinsic, not InterlockedCompareExchange API.

      • Georg Rottensteiner

        I stand corrected. You’re right. I’ve missed the _ prefix on a quick glance.

  • Cole Tobin

    Imagine the concept of there being languages other than C and C++!

    • Stacy Dudovitz

      Such as what, VB6?😂🤣

  • Neil Rashbrook

    And it does also mean that if some retrocomputing fan finds some application written for Windows NT 3.1 linked to the Interlocked functions there’s a good chance that it will still run on Windows 11.

    • Joshua Hudson

      I call these functions today. They take a guaranteed 32 bit integer instead of an _Atomic.