Skip to content

STM

Module STM provides access to a built-in Software Transactional Memory data structure, which can be thought of as a mutable map, safe from concurrent access.

Usage

There may be multiple instances of STM created in Yona, and they live completely independently to each other. Any error raised by functions in this module raise an exception of type :stm. Any expression inside the body of a context manager will have implicit access to the transaction from its scope.

Instantiating a new STM

In order to use an STM for read/write operations, one must first create the STM itself. Reference to the STM instance will be used by all other functions. STM itself is of a special type stm.

Example:

stm = STM::new

Creating a var - key for some value in the STM

STM uses concepts of vars, which are references to the STM, and they are actually their own special type in Yona.

Creating a new var:

var = STM::var stm initial_value

Creating a new var requires the STM instance and an initial value this var holds.

Starting a read-only transaction

Function read_tx creates a read-only transaction wrapped in a context manager. It takes a reference to the STM system and returns the context manager.

Access the STM in a transaction:

with STM::read_tx stm
    STM::run (\-> check_balance)
end

Starting a read-write transaction

Function write_tx creates a read-write transaction wrapped in a context manager. It takes a reference to the STM system and returns the context manager.

Access the STM in a transaction:

with STM::write_tx stm
    STM::run (\-> withdraw)
end

Note that passing a zero argument lambda requires it to be wrapped in another lambda, this is to prevent its eager evaluation.

Reading a value of a var

A var may be read either inside or outside of a transaction. Reading a var outside of a transaction, aka a dirty read, may provide a value that has been modified by another running transaction and not yet committed. Funciton read expects one argument, the var and returns a value this var contains.

Example:

value = STM::read var

Writing to a var

Function var must be called within a transaction. It expects var and the new value to be written. This function returns a ().

Example:

STM::write var new_value

Protecting a var from a concurrent write in another transaction

Function protect ensures that a var cannot be overriden from another transaction. If such change did occur, the current transaction would fail. This function expects a var and returns a ().

Example:

STM::protect var

Complete example

The following example shows a simple program for withdrawing money from an account. 10 currency is withdrawn 100 times:

let
    stm = STM::new
    balance = STM::var stm 1000f

    max_iterations = 100

    run = \i -> case i of
      x | x >= max_iterations -> STM::read balance
      x -> do
        with STM::write_tx stm
            let
                old_balance = STM::read balance
            in
                STM::write balance (old_balance - 10f)
        end

        run (i + 1)
      end
    end
in
    run 0

Last update: August 17, 2020