diff options
author | lukechampine <luke.champine@gmail.com> | 2016-04-03 13:54:52 -0400 |
---|---|---|
committer | lukechampine <luke.champine@gmail.com> | 2016-04-03 13:54:52 -0400 |
commit | 680211145fb0a720505eead0b9334451b8466916 (patch) | |
tree | f5190c512d87060738cc47702b8caaaa1c763827 /README.md | |
parent | go fmt (diff) | |
download | stm-680211145fb0a720505eead0b9334451b8466916.tar.gz stm-680211145fb0a720505eead0b9334451b8466916.tar.xz |
better pointer documentation
Diffstat (limited to 'README.md')
-rw-r--r-- | README.md | 37 |
1 files changed, 37 insertions, 0 deletions
@@ -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 |