on cd23ade help sign in
237 lines 6.6 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`, `|commit %home` 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:
61### parent.hoon
63```hoon
64/- spider
65/+ *strandio
66=, strand=strand:spider
67^- thread:spider
68|= arg=vase
69=/ m (strand ,vase)
70^- form:m
71;< =bowl:spider bind:m get-bowl
72=/ tid `@ta`(cat 3 'strand_' (scot %uv (sham %child eny.bowl)))
73;< ~ bind:m (watch-our /awaiting/[tid] %spider /thread-result/[tid])
74;< ~ bind:m %- poke-our
75 :* %spider
76 %spider-start
77 !>([`tid.bowl `tid %child !>(~)])
78 ==
79;< =cage bind:m (take-fact /awaiting/[tid])
80;< ~ bind:m (take-kick /awaiting/[tid])
81?+ p.cage ~|([%strange-thread-result p.cage %child tid] !!)
82 %thread-done (pure:m q.cage)
83 %thread-fail (strand-fail !<([term tang] q.cage))
84==
85```
87### child.hoon
89```hoon
90/- spider
91/+ *strandio
92=, strand=strand:spider
93=>
94|%
95++ url "https://www.whatsthelatestbasehash.com/"
96--
97^- thread:spider
98|= arg=vase
99=/ m (strand ,vase)
100^- form:m
101;< =cord bind:m (fetch-cord url)
102=/ hash-as-cord `@t`(end [3 (sub (met 3 cord) 1)] cord)
103=/ hash `@uv`(slav %uv hash-as-cord)
104(pure:m !>(hash))
105```
107`child.hoon` simply grabs the latest base hash from https://www.whatsthelatestbasehash.com/ and returns it.
109`parent.hoon` is a bit more complicated so we'll look at it line-by-line
111```hoon
112;< =bowl:spider bind:m get-bowl
113```
115First we grab the bowl
117```hoon
118=/ tid `@ta`(cat 3 'strand_' (scot %uv (sham %child eny.bowl)))
119```
121Then we generate a `tid` (thread ID) for the thread we're gonna start
123```hoon
124;< ~ bind:m (watch-our /awaiting/[tid] %spider /thread-result/[tid])
125```
127We pre-emptively subscribe for the result. Spider sends the result at `/thread-result/<tid>` so that's where we subscribe.
129```hoon
130;< ~ bind:m %- poke-our
131 :* %spider
132 %spider-start
133 !>([`tid.bowl `tid %child !>(~)])
134 ==
135```
137Spider takes a poke with a mark %spider-start and a vase containing `[parent=(unit tid) use=(unit tid) file=term =vase]` to start a thread, where:
139* `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.
140* `use` is the thread ID for the thread we're creating
141* `file` is the filename of the thread we want to start
142* `vase` is the vase it will be given as an argument when it's started
144```hoon
145;< =cage bind:m (take-fact /awaiting/[tid])
146```
148We wait for a fact which will be the result of the thread.
150```hoon
151;< ~ bind:m (take-kick /awaiting/[tid])
152```
154Spider will kick us from the subscription when it ends the thread so we also take that kick.
156```hoon
157?+ p.cage ~|([%strange-thread-result p.cage %child tid] !!)
158 %thread-done (pure:m q.cage)
159 %thread-fail (strand-fail !<([term tang] q.cage))
160==
161```
163Finally 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.
165## Stop a thread
167### parent.hoon
169```hoon
170/- spider
171/+ *strandio
172=, strand=strand:spider
173^- thread:spider
174|= arg=vase
175=/ m (strand ,vase)
176^- form:m
177;< =bowl:spider bind:m get-bowl
178=/ tid `@ta`(cat 3 'strand_' (scot %uv (sham %child eny.bowl)))
179%- (slog leaf+"Starting child thread..." ~)
180;< ~ bind:m %- poke-our
181 :* %spider
182 %spider-start
183 !>([`tid.bowl `tid %child !>(~)])
184 ==
185;< ~ bind:m (sleep ~s5)
186%- (slog leaf+"Stopping child thread..." ~)
187;< ~ bind:m %- poke-our
188 :* %spider
189 %spider-stop
190 !>([tid %.y])
191 ==
192;< ~ bind:m (sleep ~s2)
193(pure:m !>("Done"))
194```
196### child.hoon
198```hoon
199/- spider
200/+ *strandio
201=, strand=strand:spider
202=>
203|%
204++ looper
205 =/ m (strand ,~)
206 ^- form:m
207 %- (main-loop ,~)
208 :~ |= ~
209 ^- form:m
210 ;< ~ bind:m (sleep `@dr`(div ~s1 2))
211 %- (slog leaf+"child thread" ~)
212 (pure:m ~)
213 ==
214--
215^- thread:spider
216|= arg=vase
217=/ m (strand ,vase)
218^- form:m
219;< ~ bind:m looper
220(pure:m !>(~))
221```
223`child.hoon` just prints to the dojo in a loop.
225`parent.hoon` starts `child.hoon`, and then pokes spider like:
227```hoon
228;< ~ bind:m %- poke-our
229 :* %spider
230 %spider-stop
231 !>([tid %.y])
232 ==
233```
235* `%spider-stop` is the mark that tells spider to kill a thread.
236* `tid` is the tid of the thread to kill
237* `%.y` tells spider to suppress traceback in the result of the killed thread. If you give it `%.n` it will include the traceback.