diff options
Diffstat (limited to 'docs/LEARN.md')
| -rw-r--r-- | docs/LEARN.md | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/docs/LEARN.md b/docs/LEARN.md index 35ee914..eae9ad4 100644 --- a/docs/LEARN.md +++ b/docs/LEARN.md @@ -1003,6 +1003,47 @@ output: 16640 ``` +## hold blocks + +actors share nothing by default: each one runs on its own copy of the program's globals and its own heap, so a global an actor changes is changed only for that actor. state that every actor sees is declared `shared` inside a top-level `hold` block, a monitor. only the functions written in the block can use its shared variables, and each call to one of them holds the block's lock for the whole call, so everything such a function does is atomic. a call from one of the block's functions to another doesn't lock again. + +using a shared variable anywhere else is an error, and so is using it in a closure, which could run after the lock is released. shared variables hold numbers or arrays of numbers; a pointer would point into one actor's heap. when a program has several hold blocks, a function of one block may call into a block declared after it, but not back into an earlier one while it holds a later one: that order rules out deadlocks between blocks, and breaking it stops the program. + +[example source](../examples/learn/36-hold.zc): + +```zc +namespace; +include rt, actor; +typecheck on; + +// one counter for every actor. only the functions written in the block can touch it, +// and each call holds the block's lock, so a read and the write after it can't interleave. +hold { + shared let hits = 0; + fn hit() { let seen = hits; hits = seen + 1; return seen; } + fn total() { return hits; } +} + +int work(int n) { let i = 0; while (i < n) { hit(); i++; } return n; } + +fn main() { + actor.Actor<int,int>* a = rt.new(actor.Actor<int,int>), b = rt.new(actor.Actor<int,int>); + a.spawn(work); b.spawn(work); + a.send(1000); b.send(1000); + a.recv(fn(int n) { return 0; }); b.recv(fn(int n) { return 0; }); + a.await(); b.await(); + rt.put_n(total()); rt.put_c(10); + a.close(); b.close(); + return 0; +} +``` + +output: + +```text +2000 +``` + ## the optional typechecker `typecheck on;` enables type checking for the declarations that follow; `typecheck off;` disables it. errors report the expected and actual types. the lifetime analyzer runs independently of this switch. a literal 0 can be a null pointer, `word` matches any type, and arrays can decay to pointers. |
