aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlukechampine <luke.champine@gmail.com>2016-03-30 16:45:25 -0400
committerlukechampine <luke.champine@gmail.com>2016-03-30 16:45:25 -0400
commitd658c1d8ef9d9dc739d9e687d018262cd435e323 (patch)
tree4bf06941fa80d5b49b011737cfd6f3aee8ead272
parentadd some helper functions (diff)
downloadstm-d658c1d8ef9d9dc739d9e687d018262cd435e323.tar.gz
stm-d658c1d8ef9d9dc739d9e687d018262cd435e323.tar.xz
add LICENSE and shorten README
-rw-r--r--LICENSE21
-rw-r--r--README.md72
2 files changed, 24 insertions, 69 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..79479d4
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Luke Champine
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index 53fdc66..abff0e4 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# stm
+[![GoDoc](https://godoc.org/github.com/lukechampine/stm?status.svg)](https://godoc.org/github.com/lukechampine/stm)
+
Package `stm` provides [Software Transactional Memory](https://en.wikipedia.org/wiki/Software_transactional_memory) operations for Go. This is
an alternative to the standard way of writing concurrent code (channels and
mutexes). STM makes it easy to perform arbitrarily complex operations in an
@@ -8,75 +10,7 @@ STM transactions are composable, whereas locking functions are not -- the
composition will either deadlock or release the lock between functions (making
it non-atomic).
-To begin, create an STM object that wraps the data you want to access
-concurrently:
-
-```go
- x := stm.NewVar(3)
-```
-You can then use the Atomically method to atomically read and/or write the the
-data. This code atomically decrements `x`:
-
-```go
- stm.Atomically(func(tx *stm.Tx) {
- cur := tx.Get(x).(int)
- tx.Set(x, cur-1)
- })
-```
-
-An important part of STM transactions is retrying. At any point during the
-transaction, you can call `tx.Retry()`, which will abort the transaction,
-but not cancel it entirely. The call to `Atomically` will block until another
-call to `Atomically` finishes, at which point the transaction will be rerun.
-Specifically, one of the values read by the transaction (via `tx.Get`) must be
-updated before the transaction will be rerun. As an example, this code will
-try to decrement `x`, but will block as long as `x` is zero:
-
-```go
- stm.Atomically(func(tx *stm.Tx) {
- cur := tx.Get(x).(int)
- if cur == 0 {
- tx.Retry()
- }
- tx.Set(x, cur-1)
- })
-```
-
-Internally, `tx.Retry` simply calls `panic(stm.Retry)`. Panicking with any
-other value will cancel the transaction; no values will be changed. However,
-it is the responsibility of the caller to catch such panics.
-
-Multiple transactions can be composed using `Select`. If the first transaction
-calls `Retry`, the next transaction will be run, and so on. If all of the
-transactions call `Retry`, the call will block and the entire selection will
-be retried. For example, this code implements the "decrement-if-nonzero"
-transaction above, but for two values. It will first try to decrement `x`,
-then `y`, and block if both values are zero.
-
-```go
- func dec(v *stm.Var) func(*stm.Tx) {
- return func(tx *stm.Tx) {
- cur := tx.Get(v).(int)
- if cur == 0 {
- tx.Retry()
- }
- tx.Set(v, cur-1)
- }
- }
-
- // Note that Select does not perform any work itself, but merely
- // returns a new transaction.
- stm.Atomically(stm.Select(dec(x), dec(y)))
-```
-
-An important caveat: transactions must not have side effects! This is because a
-transaction may be restarted several times before completing, meaning the side
-effects may execute more than once. This will almost certainly cause incorrect
-behavior. One common way to get around this is to build up a list of operations
-to perform inside the transaction, and then perform them after the transaction
-completes.
-
-The `stm` API tries to mimic that of Haskell's `Control.Concurrent.STM`, but
+The `stm` API tries to mimic that of Haskell's [`Control.Concurrent.STM`](https://hackage.haskell.org/package/stm-2.4.4.1/docs/Control-Concurrent-STM.html), but
this is not entirely possible due to Go's type system; we are forced to use
`interface{}` and type assertions. Furthermore, Haskell can enforce at compile
time that STM variables are not modified outside the STM monad. This is not