Crate stm [−] [src]
This library implements software transactional memory, often abbreviated with STM.
It is designed closely to haskells STM library. Read Simon Marlow's Parallel and Concurrent Programming in Haskell for more info. Especially the chapter about Performance is also important for using STM in rust.
With locks the sequence of two threadsafe actions is no longer threadsafe because other threads may interfer in between of these actions. Applying another lock may lead to common sources of errors like deadlocks and forgotten locks.
Unlike locks Software transactional memory is composable. It is typically implemented by writing all read and write operations in a log. When the action has finished, the reads are checked for consistency and depending on the result either the writes are committed in a single atomic operation or the result is discarded and the computation run again.
Usage
STM operations are safed inside the type STM<T>
where T
is the return type of the inner operation. They are created with stm!
:
let transaction = stm!({ // some action // return value (or empty for unit) });
and can then be run by calling.
transaction.atomically();
For running an STM-Block inside of another
use the macro stm_call!
:
use stm::Var; let var = Var::new(0); let modify = stm!({ var.write(42); }); let x = stm!({ stm_call!(modify); var.read() // return the value saved in var }).atomically(); println!("var = {}", x);
STM safety
Software transactional memory is completely safe in the terms that rust considers safe. Still there are multiple rules that you should obey when dealing with software transactional memory:
- Don't run code with side effects, especially no IO-code, because stm is designed to be run multiple times. Return a closure if you have to.
- Don't run an STM-Block by calling
STM::atomically
inside of another because your thread will immediately panic. When you use STM in the inner of a function then return a STM-Object instead so that callers can safely compose it into larger blocks. - Don't mix locks and STM. Your code will easily deadlock and slow down on unpredictably.
- When you put an
Arc
into aVar
don't use inner mutability to modify it since the inner still points to the original value. - Don't call
Var::read
orVar::write
from outside of a STM block. Instead start a STM or useVar::read_atomic
for it.
Speed
Generally keep your atomic blocks as small as possible bacause the more time you spend the more likely it is to collide with other threads. For STM reading vars is quite slow because it need to look them up in the log every time they are written to and every used var increases the chance of collisions. You should keep the amount of accessed variables as low as needed.
Macros
stm! |
declare a block that uses STM |
stm_call! |
call a STM function from inside of a STM block |
Structs
STM |
class representing a STM computation |
Var |
A variable that can be used in a STM-Block |
Enums
StmResult |
a result of each step of a STM calculation |
Functions
retry |
call retry in |