Today, I’m releasing an open source library called Mintomic. Mintomic is an API for low-level lock-free programming in C and C++. It runs on a variety of platforms including Windows, Linux, MacOS, iOS and Xbox 360. Mintomic’s goals are to be efficient, straightforward, and (mostly) compatible with older compilers.
View the documentation |
View on GitHub |
Mintomic (short for “minimal atomic”) draws lot of inspiration from the C/C++11 atomic library standards, with an important exception: In Mintomic, all atomic operations are “relaxed”. The only way to enforce memory ordering is with explicit fences. Here’s an example taken from my post about weak hardware ordering, rewritten using Mintomic:
// Define a shared atomic variable: mint_atomic32_t flag; void IncrementSharedValue10000000Times(TimeWaster& tw) { int count = 0; while (count < 10000000) { tw.wasteRandomCycles(); // Atomic read-modify-write operation: if (mint_compare_exchange_strong_32_relaxed(&flag, 0, 1) == 0) { mint_thread_fence_acquire(); // Acquire fence g_sharedValue++; mint_thread_fence_release(); // Release fence // Atomic store: mint_store_32_relaxed(&flag, 0); count++; } } }
I started Mintomic out of the desire for a better way to share examples of lock-free programming on this blog. So why not just use C++11 atomics instead?
- Availability. Some readers are likely stuck using Visual Studio 2010, GCC 4.3, or an older compiler in which C++11 atomics are not available.
- Efficiency. The C++11 atomic library standard does not guarantee an efficient implementation, only a correct one. Technically, it does not even guarantee your code will be lock-free. Mintomic, on the other hand, always aims to generate optimal lock-free machine code on the platforms it supports.
- Lower learning curve. Mintomic asks you to keep fewer concepts in your head than C++11 atomics. I actually hope Mintomic will serve as a stepping stone towards learning C++11 atomics, since it maps to a subset of the same functionality and uses a similar naming convention.
In particular, because all of Mintomic’s atomic operations are relaxed, there are no sequentially consistent data types. This is different from C++11’s atomic library standard, where every atomic operation is sequentially consistent by default. To remind you of the difference, all atomic functions in Mintomic have the _relaxed
suffix on their names.
Mintomic comes with a test suite which you can build and run yourself. The only requirement is CMake. This test suite helps ensure that Mintomic was implemented correctly on each platform, while bringing the library to life with a working set of examples. Here’s what its output looks like as a 64-bit Windows application:
And here it is on an iPhone 4S:
Every test case with a _fail
suffix on its name contains an intentional bug. These tests are allowed to fail, and in general, designed to do so, in the same spirit as previous blog posts written here. You’ll notice that on 64-bit Windows, more of these test cases pass (10/11) than on the iPhone (6/11). The point is to show how incorrect lock-free code may succeed on certain platforms out of luck, depending on things like compiler ordering, machine word size and hardware memory model.
To support this test suite, Mintomic also comes with MintSystem, a portable C module to create and manipulate threads and semaphores, and MintPack, a collection of useful data structures in C++.
I’ll admit, the existence of a library like Mintomic is a bit funny, for several reasons. First, Mintomic is squarely focused on low-level lock-free programming, providing only relaxed atomics and standalone memory fences – two things which some C++ experts claim you should avoid using. Second, lock-free programming is definitely not something which every programmer will ever need to do, and in a real project, it typically accounts for a very tiny fraction of the codebase. And finally, some programmers believe that lock-free programming can always be encapsulated using patterns and techniques such as the actor model, goroutines, or functional programming.
Meanwhile, in the games industry at least, we use Mintomic-like primitives to achieve real-world performance gains on a regular basis. Not out of hubris, but because we have deadlines and performance targets, and there are (rare) occasions when it genuinely makes a difference. I’m certain that in the long term, low-level lock-free programming will continue to play a role in games, audio synthesis, financial trading software – anywhere that parallel, high-contention tasks must be optimized for latency. Therefore, it’s worth trying to stop messing up, which is why I keep blogging about it.
I think Mintomic turned out decent, though there are still things to improve. Feedback and suggestions are welcome! In the meantime, stay tuned for further examples using Mintomic.