I've built the combinatorial STM library on top of some functional programming ideas. It doesn't require any compiler support (except it uses C++17), doesn't bring a new syntax. In general, it adopts the interface of the STM library from Haskell.
So, my library has several nice properties:
- Monadically combinatorial. Every transaction is a computation inside the custom monad named
STML
. You can combine monadic transactions into more big monadic transactions.
- Transactions are separated from data model. You construct your concurrent data model with transactional variables (
TVars
) and run transactions over it.
- There is
retry
combinator. It allows you to rerun the transaction. Very useful to build short and understandable transactions.
- There are different monadic combinators to express computations shortly.
- There is
Context
. Every computation should be run in some context, not in the global runtime. So you can have many different contexts if you need several independent STM clusters.
- The implementation is quite simple conceptually. At least, the reference implementation in Haskell is so, but I had to reinvent several approaches for C++ implementation due to the lack of a good support of Functional Programming.
The library shows very nice stability and robustness, even if we consider it experimental. Moreover, my approach opens a lot of possibilities to improve the library by performance, features, comprehensiveness, etc.
To demonstrate its work, I've solved the Dining Philosophers
task. You can find the code in the links below. Sample transaction:
STML<bool> takeFork(const TVar<Fork>& tFork)
{
STML<bool> alreadyTaken = withTVar(tFork, isForkTaken);
STML<Unit> takenByUs = modifyTVar(tFork, setForkTaken);
STML<bool> success = sequence(takenByUs, pure(true));
STML<bool> fail = pure(false);
STML<bool> result = ifThenElse(alreadyTaken, fail, success);
return result;
};
UPDATE
I've wrote a tutorial, you can find it here.