on c8ea9f2 help sign in
241 lines 7.0 kB history raw
1+++
2title = "Child Thread"
3weight = 2
4template = "doc.html"
5+++
7Here's a simple example of a thread that starts another thread:
9#### `parent.hoon`
11```hoon
12/- spider
13/+ *strandio
14=, strand=strand:spider
15^- thread:spider
16|= arg=vase
17=/ m (strand ,vase)
18^- form:m
19;< tid=tid:spider bind:m (start-thread %child)
20(pure:m !>(~))
21```
23#### `child.hoon`
25```hoon
26/- spider
27/+ *strandio
28=, strand=strand:spider
29^- thread:spider
30|= arg=vase
31=/ m (strand ,vase)
32^- form:m
33%- (slog leaf+"foo" ~)
34(pure:m !>(~))
35```
37Save `parent.hoon` and `child.hoon` in `/ted` of the `%base` desk, `|commit %base` and run `-parent`. You should see something like:
39```
40foo
41> -parent
43```
45`parent.hoon` just uses the `strandio` function `start-thread` to start `child.hoon`, and `child.hoon` just prints `foo` to the dojo. Since we got `foo` we can tell the second thread did, in fact, run.
47```hoon
48;< tid=tid:spider bind:m (start-thread %child)
49```
51See here how we gave `start-thread` the name of the thread to run. It returns the `tid` of the thread, which we could then use to poke it or whatever.
53`start-thread` handles creating the `tid` for the thread so is quite convenient.
55Note that threads we start this way will be a child of the thread that started them, and so will be killed when the parent thread ends.
57## Start thread and get its result
59If we want to actually get the result of the thread we started, it's slightly more complicated.
60We note that this is mostly the same as `await-thread:strandio`.
62#### `parent.hoon`
64```hoon
65/- spider
66/+ *strandio
67=, strand=strand:spider
68^- thread:spider
69|= arg=vase
70=/ m (strand ,vase)
71^- form:m
72;< =bowl:spider bind:m get-bowl
73=/ tid `@ta`(cat 3 'strand_' (scot %uv (sham %child eny.bowl)))
74;< ~ bind:m (watch-our /awaiting/[tid] %spider /thread-result/[tid])
75;< ~ bind:m %- poke-our
76 :* %spider
77 %spider-start
78 !>([`tid.bowl `tid byk.bowl(r da+now.bowl) %child !>(~)])
79 ==
80;< =cage bind:m (take-fact /awaiting/[tid])
81;< ~ bind:m (take-kick /awaiting/[tid])
82?+ p.cage ~|([%strange-thread-result p.cage %child tid] !!)
83 %thread-done (pure:m q.cage)
84 %thread-fail (strand-fail !<([term tang] q.cage))
85==
86```
88#### `child.hoon`
90```hoon
91/- spider
92/+ *strandio
93=, strand=strand:spider
94=>
95|%
96++ url "https://www.whatsthelatestbasehash.com/"
97--
98^- thread:spider
99|= arg=vase
100=/ m (strand ,vase)
101^- form:m
102;< =cord bind:m (fetch-cord url)
103=/ hash-as-cord `@t`(end [3 (sub (met 3 cord) 1)] cord)
104=/ hash `@uv`(slav %uv hash-as-cord)
105(pure:m !>(hash))
106```
108`child.hoon` simply grabs the latest base hash from https://www.whatsthelatestbasehash.com/ and returns it.
110`parent.hoon` is a bit more complicated so we'll look at it line-by-line
112```hoon
113;< =bowl:spider bind:m get-bowl
114```
116First we grab the bowl
118```hoon
119=/ tid `@ta`(cat 3 'strand_' (scot %uv (sham %child eny.bowl)))
120```
122Then we generate a `tid` (thread ID) for the thread we're gonna start
124```hoon
125;< ~ bind:m (watch-our /awaiting/[tid] %spider /thread-result/[tid])
126```
128We pre-emptively subscribe for the result. Spider sends the result at `/thread-result/<tid>` so that's where we subscribe.
130```hoon
131;< ~ bind:m %- poke-our
132 :* %spider
133 %spider-start
134 !>([`tid.bowl `tid byk.bowl(r da+now.bowl) %child !>(~)])
135 ==
136```
138Spider takes a poke with a mark %spider-start and a vase containing `[parent=(unit tid) use=(unit tid) =beak file=term =vase]` to start a thread, where:
140- `parent` is an optional parent thread. In this case we say the parent is our tid. Specifying a parent means the child will be killed if the parent ends.
141- `use` is the thread ID for the thread we're creating
142- `beak` is a `[p=ship q=desk r=case]` triple which specifies the desk and
143 revision containing the thread we want to run. In this case we just use
144 `byk.bowl`, but with the date of revision `q` changed to `now.bowl`.
145- `file` is the filename of the thread we want to start
146- `vase` is the vase it will be given as an argument when it's started
148```hoon
149;< =cage bind:m (take-fact /awaiting/[tid])
150```
152We wait for a fact which will be the result of the thread.
154```hoon
155;< ~ bind:m (take-kick /awaiting/[tid])
156```
158Spider will kick us from the subscription when it ends the thread so we also take that kick.
160```hoon
161?+ p.cage ~|([%strange-thread-result p.cage %child tid] !!)
162 %thread-done (pure:m q.cage)
163 %thread-fail (strand-fail !<([term tang] q.cage))
164==
165```
167Finally we test whether the thread produced a `%thread-done` or a `%thread-fail`. These are the two possible marks produced by spider when it returns the results of a thread. A `%thread-done` will contain a vase with the result, and a `%thread-fail` will contain an error message and traceback, so we see which it is and then either produce the result with `pure` or trigger a `%thread-fail` with the error we got from the child.
169## Stop a thread
171#### `parent.hoon`
173```hoon
174/- spider
175/+ *strandio
176=, strand=strand:spider
177^- thread:spider
178|= arg=vase
179=/ m (strand ,vase)
180^- form:m
181;< =bowl:spider bind:m get-bowl
182=/ tid `@ta`(cat 3 'strand_' (scot %uv (sham %child eny.bowl)))
183%- (slog leaf+"Starting child thread..." ~)
184;< ~ bind:m %- poke-our
185 :* %spider
186 %spider-start
187 !>([`tid.bowl byk.bowl(r da+now.bowl) `tid %child !>(~)])
188 ==
189;< ~ bind:m (sleep ~s5)
190%- (slog leaf+"Stopping child thread..." ~)
191;< ~ bind:m %- poke-our
192 :* %spider
193 %spider-stop
194 !>([tid %.y])
195 ==
196;< ~ bind:m (sleep ~s2)
197(pure:m !>("Done"))
198```
200#### `child.hoon`
202```hoon
203/- spider
204/+ *strandio
205=, strand=strand:spider
206=>
207|%
208++ looper
209 =/ m (strand ,~)
210 ^- form:m
211 %- (main-loop ,~)
212 :~ |= ~
213 ^- form:m
214 ;< ~ bind:m (sleep `@dr`(div ~s1 2))
215 %- (slog leaf+"child thread" ~)
216 (pure:m ~)
217 ==
218--
219^- thread:spider
220|= arg=vase
221=/ m (strand ,vase)
222^- form:m
223;< ~ bind:m looper
224(pure:m !>(~))
225```
227`child.hoon` just prints to the dojo in a loop.
229`parent.hoon` starts `child.hoon`, and then pokes spider like:
231```hoon
232;< ~ bind:m %- poke-our
233 :* %spider
234 %spider-stop
235 !>([tid %.y])
236 ==
237```
239- `%spider-stop` is the mark that tells spider to kill a thread.
240- `tid` is the tid of the thread to kill
241- `%.y` tells spider to suppress traceback in the result of the killed thread. If you give it `%.n` it will include the traceback.