1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
package stm_test
import (
"github.com/anacrolix/stm"
)
func Example() {
// create a shared variable
n := stm.NewVar(3)
// read a variable
var v int
stm.Atomically(stm.VoidOperation(func(tx *stm.Tx) {
v = n.Get(tx)
}))
// or:
v = stm.AtomicGet(n)
_ = v
// write to a variable
stm.Atomically(stm.VoidOperation(func(tx *stm.Tx) {
n.Set(tx, 12)
}))
// or:
stm.AtomicSet(n, 12)
// update a variable
stm.Atomically(stm.VoidOperation(func(tx *stm.Tx) {
cur := n.Get(tx)
n.Set(tx, cur-1)
}))
// block until a condition is met
stm.Atomically(stm.VoidOperation(func(tx *stm.Tx) {
cur := n.Get(tx)
if cur != 0 {
tx.Retry()
}
n.Set(tx, 10)
}))
// or:
stm.Atomically(stm.VoidOperation(func(tx *stm.Tx) {
cur := n.Get(tx)
tx.Assert(cur == 0)
n.Set(tx, 10)
}))
// select among multiple (potentially blocking) transactions
stm.Atomically(stm.Select(
// this function blocks forever, so it will be skipped
stm.VoidOperation(func(tx *stm.Tx) { tx.Retry() }),
// this function will always succeed without blocking
stm.VoidOperation(func(tx *stm.Tx) { n.Set(tx, 10) }),
// this function will never run, because the previous
// function succeeded
stm.VoidOperation(func(tx *stm.Tx) { n.Set(tx, 11) }),
))
// since Select is a normal transaction, if the entire select retries
// (blocks), it will be retried as a whole:
x := 0
stm.Atomically(stm.Select(
// this function will run twice, and succeed the second time
stm.VoidOperation(func(tx *stm.Tx) { tx.Assert(x == 1) }),
// this function will run once
stm.VoidOperation(func(tx *stm.Tx) {
x = 1
tx.Retry()
}),
))
// But wait! Transactions are only retried when one of the Vars they read is
// updated. Since x isn't a stm Var, this code will actually block forever --
// but you get the idea.
}
|