aboutsummaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
authorlukechampine <luke.champine@gmail.com>2016-04-03 13:54:52 -0400
committerlukechampine <luke.champine@gmail.com>2016-04-03 13:54:52 -0400
commit680211145fb0a720505eead0b9334451b8466916 (patch)
treef5190c512d87060738cc47702b8caaaa1c763827 /README.md
parentgo fmt (diff)
downloadstm-680211145fb0a720505eead0b9334451b8466916.tar.gz
stm-680211145fb0a720505eead0b9334451b8466916.tar.xz
better pointer documentation
Diffstat (limited to 'README.md')
-rw-r--r--README.md37
1 files changed, 37 insertions, 0 deletions
diff --git a/README.md b/README.md
index b968c31..d6adcf6 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,13 @@ Another significant departure is that `stm.Atomically` does not return a value.
This shortens transaction code a bit, but I'm not 100% it's the right decision.
(The alternative would be for every transaction function to return an `interface{}`.)
+Unlike Haskell, data in Go is not immutable by default, which means you have
+to be careful when using STM to manage pointers. If two goroutines have access
+to the same pointer, it doesn't matter whether they retrieved the pointer
+atomically; modifying the pointer can still cause a data race. To resolve
+this, either use immutable data structures, or replace pointers with STM
+variables. A more concrete example is given below.
+
It remains to be seen whether this style of concurrency has practical
applications in Go. If you find this package useful, please tell me about it!
@@ -82,6 +89,36 @@ stm.Atomically(stm.Select(
See [example_santa_test.go](example_santa_test.go) for a more complex example.
+## Pointers
+
+Don't use stm to manage pointers!
+
+```go
+p := stm.NewVar([]byte{1,2,3})
+stm.Atomically(func(tx *stm.Tx) {
+ b := tx.Get(p).([]byte)
+ b[0] = 7
+ tx.Set(p, b)
+})
+```
+
+This transaction looks innocent enough, but it has a hidden side effect: the
+modification of b is visible outside the transaction. Instead of modifying
+pointers directly, prefer to operate on immutable values as much as possible.
+Following this advice, we can rewrite the transaction to perform a copy:
+
+```go
+stm.Atomically(func(tx *stm.Tx) {
+ b := tx.Get(p).([]byte)
+ c := make([]byte, len(b))
+ copy(c, b)
+ c[0] = 7
+ tx.Set(p, c)
+})
+```
+
+This is less efficient, but it preserves atomicity.
+
## Benchmarks
In synthetic benchmarks, STM seems to have a 1-5x performance penalty compared