Software Transactional Memory in C++: Pure Functional Approach (tutorial) This article presents a tutorial on a pure functional C++ library for Software Transactional Memory (STM), which aims to simplify parallel and concurrent programming by allowing developers to build and evaluate concurrent data models in transactions without manual synchronization. The author explains that STM resolves conflicts between competing transactions automatically, ensuring the data model remains valid through atomic updates, and highlights that the library's interface is similar to Haskell's STM, making it composable and easy to use. Software Transactional Memory in C++: pure functional approach Tutorial In this article I’ll tell you about my pure functional library for Software Transactional Memory STM that I’ve built in C++. I adopted some advanced functional programming concepts that make it composable and convenient to use. Its implementation is rather small and robust, which differentiates the library from competitors. Let’s discuss what STM is and how to use it. - Intro Intro - Links Links - Software Transactional Memory Software-Transactional-Memory - STM basics STM-basics - Composable transactions Composable-transactions - Dining Philosophers: The task Dining-Philosophers-The-task - Dining Philosophers: Data model Dining-Philosophers-Data-model - Dining Philosophers: Behavior model Dining-Philosophers-Behavior-model - Dining Philosophers: Multithreaded evaluation Dining-Philosophers-Multithreaded-evaluation - Conclusion Conclusion - Additional materials Additional-materials --- Intro Parallel and concurrent programming is hard. We fall to this opinion once we’ve faced that our multithreading code isn’t working as expected. It was fine for a while, but then something bad is happened. Either the system stuck in a deadlock, or it has returned some invalid data due to race condition, or even crashed: no matter the happening, the system went berserk and started doing wrong things. This is hard to predict, hard to debug and certainly hard to test because multithreading bugs are quite sneaky and we cannot be sure the code is totally free from them. Software Transactional Memory is introduced to solve many of these issues and provide an easy-to-use concurrency approach. With STM, you build your concurrent data model and then start evaluating it in different threads. STM makes a code running almost safe. It removes many problems usually following parallel code as a class. STM code doesn’t contain any synchronization bits and has a well-defined behavior, so it’s much easier to write it correctly. STM can’t completely save you from the problems, but it significantly reduces the complexity of parallel code, so finding problems becomes a walk in a forest. Sounds good, right? Let’s see how STM approaches this goal. Links The cpp stm free library https://github.com/graninas/cpp stm free Dining Philosophers sample https://github.com/graninas/cpp philosophers stm More STM samples https://github.com/graninas/stm samples C++ Russia 2018 talk slides Eng https://www.slideshare.net/alexandrgranin/software-transactional-memory-pure-functional-approach C++ Russia 2018 talk Rus https://youtu.be/VHZPcz8HwZs Software Transactional Memory The idea of STM is similar to transactional databases. Like them, you have some shared mutable data model and can evaluate safe transactional updates over it. Unlike databases, STM is not an external storage, it’s your application’s state. Notably, threaded transactions usually work on different parts of the model and they are isolated from each other. Transactions are able to update the model simultaneously. Well, to some degree; but sometimes it happens so that the transactions want to change the same part of the model. Just allowing them to do this is not a solution: simultaneous writing of the same shared resource is a guaranteed race condition. In the STM terminology, this situation is known as conflict. STM is responsible for solving conflicts in the background. It decides what transaction should commit the result, and what transaction should be restarted. You don’t need to control this behavior, STM has own tools to synchronize the two competing transactions. You’ll just be knowing that the data model stays valid all the time because of atomic updates STM does using the transactions. Now I’ll show you how to construct concurrent data models and write transactions. I’ll be using my library, but other STM libraries have similar notions so it probably shouldn’t be a problem to catch the idea they all have in common. I’d also say my library has the same interface as Haskell’s one http://hackage.haskell.org/package/stm , and you’ll see it’s really easy to learn. So maybe learning it would be like learning Haskell a little bit. I hope, it will inspire you, not scare You’ll see it’s easy and quite fun. STM basics Every implementation of STM brings a way to build any kind of data models you need for your tasks. But you can’t just define a variable and work with it inside a transaction. It won’t be thread-safe because the variable is not atomic. Ok, you’re right there is std::atomic , and under some circumstances, it can be a better solution than STM. After all, if you have just one shared variable let’s say a counter of type int , involving STM would be like renting a helicopter to visit a coffee shop. It becomes more profitable when your data model is big enough, or when the logic of parallel code tends to become too sophisticated. We’ll start from simple cases, though. In my library, a basic notion of shared resource is represented by TVar - namely, “transactional variable” . Here: cpp TVar