ref: 577f8a21ded3a49c799ee49b90508801f1361842
parent: 5bd50f13c315024164a221eb5a86edabf412b4d1
author: seh <henesy.dev@gmail.com>
date: Mon Mar 18 11:42:43 EDT 2019
add spawn and channels examples
--- a/Channels/README.md
+++ b/Channels/README.md
@@ -8,12 +8,59 @@
## Source
+### chans.b:33,36
+This statement shows three channels being made.
-## Demo
+`done` is an unbuffered channel which transports integer values.
+`msgChan` is an unbuffered channel, instantiated using buffered channel syntax, which transports strings.
+`numChan` is a buffered channel which transports a tuple representing an integer pair.
+### chans.b:38
+
+The `spawn` statement is used to create a new process running a given function, in this case `summer()`.
+
+### chans.b:40,45
+
+This section loads number pairs from the variable `i` and the number 2 from 0 to 14, covering 15 total iterations. After the iterative statement completes, a (later discarded) value is passed to the channel `done`. The first (and only) value in `msgChan` is then read out and printed.
+
+Note: Writing to a channel whose buffer (or lack thereof) is currently full is a blocking operation. Similarly, reading from a channel whose buffer (or lack thereof) is currently empty is a blocking operation.
+
+### chans.b:13,28
+
+The function `summer()` operates an infinite loop which operates a single `alt` statement which is similar to a switch-case statement which operates on the presence of values within a channel.
+
+The three channels are used to coordinate operation between the two processes.
+
+`num` is checked first and a tuple of values is pulled out: a value and a power to raise said value to. The `n^p` operation is shown as `n**p` in Limbo, with the result being added to sum's current value.
+
+`done` is checked after `num` has no more values in its buffer. If a value is found, the sum is stringified and passed down `msg` and the looping condition is unset.
+
+The default value, indicated by `*=>`, is used when no channels have a value, so we sleep the current process for 5ms to de-schedule ourselves in case some form of scheduling is holding up our communications.
+
+## Demo
+
+ ; limbo chans.b
+ ; chans
+ Sum: 0
+ Sum: 1
+ Sum: 5
+ Sum: 14
+ Sum: 30
+ Sum: 55
+ Sum: 91
+ Sum: 140
+ Sum: 204
+ Sum: 285
+ Sum: 385
+ Sum: 506
+ Sum: 650
+ Final sum: 650
+ ;
+
## Exercises
--
+- Can you pass an ADT over a channel?
+- What happens if you pass a `ref` type over a channel?
--- a/Channels/chans.b
+++ b/Channels/chans.b
@@ -10,11 +10,46 @@
init: fn(nil: ref Draw->Context, nil: list of string);
};
+summer(done: chan of int, msg: chan of string, num: chan of (int, int)) {
+ sum := big 0;
+ run := 1;
+
+ while(run)
+ alt {
+ (n, p) := <-num =>
+ sum += big n**p;
+ print("Sum: %bd\n", sum);
+ <-done =>
+ msg <-= string sum;
+ run = 0;
+ * =>
+ sys->sleep(5);
+ }
+}
+
init(nil: ref Draw->Context, nil: list of string) {
sys = load Sys Sys->PATH;
-
+ n := 4;
+ done := chan of int;
+ msgChan := chan[0] of string;
+ numChan := chan[n] of (int, int);
+ spawn summer(done, msgChan, numChan);
+
+ for(i := 0; i < 15; i++)
+ numChan <-= (i, 2);
+
+ done <-= 0;
+
+ print("Final sum: %s\n", <-msgChan);
+
+ buf := chan[20] of int;
+
+ print("Len: %d\n", len buf);
+
+ for(i = 0; i < 5; i++)
+ buf <-= i;
+
exit;
}
-
--- a/README.md
+++ b/README.md
@@ -38,6 +38,8 @@
- [Slices](./Slices)
- [Functions](./Functions)
- [Function References](./Function-Refs)
+- [Spawn](./Spawn)
+- [Channels](./Channels)
- [Abstract Data Types](./ADTs)
- [Modules](./Modules)
- [Generics, Picks, and Interfaces (kind of)](./Generics)
--- /dev/null
+++ b/Spawn/README.md
@@ -1,0 +1,39 @@
+# Spawn
+
+Limbo supports the creation of processes operating on a given function via the `spawn` statement. Functions passed to spawn cannot have a return value.
+
+Inferno processes share memory with their parent processes which spawn them, bar the process's respective stack. Inferno processes are pre-emptively scheduled by the Inferno kernel. These processes are analogous, but not equivocal to, threads in unix-like systems.
+
+Synchronization between processes is recommended to be done through [channels](../Channels).
+
+For further reading on potential inspirations for Inferno processes, see [rfork(2)](http://man.cat-v.org/9front/2/fork).
+
+## Source
+
+### spawn.b:31,40
+
+This section spawns four processes all of which will attempt to print to their standard output. Two functions spawn running the `quacker()` function and two function spawn running the `summer()` function with varying arguments.
+
+Note: The call to `sleep()` in this context within the `init()` function.
+
+## Demo
+
+ ; limbo spawn.b
+ ; spawn
+ quack!
+ Sum (2): 0
+ quack!
+ Sum (3): 0
+ Sum (2): 1
+ Sum (3): 1
+ Sum (2): 3
+ Sum (3): 3
+ Final sum (2): 3
+ Sum (3): 6
+ Final sum (3): 6
+ ;
+
+## Exercises
+
+- How many different orders do you see the print statements occur in?
+- What happens if you remove the sleep?
--- /dev/null
+++ b/Spawn/spawn.b
@@ -1,0 +1,43 @@
+implement Spawn;
+
+include "sys.m";
+include "draw.m";
+
+sys: Sys;
+print: import sys;
+
+Spawn: module {
+ init: fn(nil: ref Draw->Context, nil: list of string);
+};
+
+summer(n: int) {
+ sum := 0;
+
+ for(i := 0; i <= n; i++) {
+ sum += i;
+ print("Sum (%d): %d\n", n, sum);
+ }
+
+ print("Final sum (%d): %d\n", n, sum);
+}
+
+quacker() {
+ print("quack!\n");
+}
+
+init(nil: ref Draw->Context, nil: list of string) {
+ sys = load Sys Sys->PATH;
+
+ spawn quacker();
+
+ spawn summer(2);
+
+ spawn quacker();
+
+ n := 3;
+ spawn summer(n);
+
+ sys->sleep(10);
+
+ exit;
+}