on 514b5fc help sign in
238 lines 6.8 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:
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 byk.bowl %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 byk.bowl `tid %child !>(~)])
134 ==
135```
137Spider 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:
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- `beak` is a `[p=ship q=desk r=case]` triple which specifies the desk and revision containing the thread we want to run. In this case we just use `byk.bowl`.
142- `file` is the filename of the thread we want to start
143- `vase` is the vase it will be given as an argument when it's started
145```hoon
146;< =cage bind:m (take-fact /awaiting/[tid])
147```
149We wait for a fact which will be the result of the thread.
151```hoon
152;< ~ bind:m (take-kick /awaiting/[tid])
153```
155Spider will kick us from the subscription when it ends the thread so we also take that kick.
157```hoon
158?+ p.cage ~|([%strange-thread-result p.cage %child tid] !!)
159 %thread-done (pure:m q.cage)
160 %thread-fail (strand-fail !<([term tang] q.cage))
161==
162```
164Finally 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.
166## Stop a thread
168#### `parent.hoon`
170```hoon
171/- spider
172/+ *strandio
173=, strand=strand:spider
174^- thread:spider
175|= arg=vase
176=/ m (strand ,vase)
177^- form:m
178;< =bowl:spider bind:m get-bowl
179=/ tid `@ta`(cat 3 'strand_' (scot %uv (sham %child eny.bowl)))
180%- (slog leaf+"Starting child thread..." ~)
181;< ~ bind:m %- poke-our
182 :* %spider
183 %spider-start
184 !>([`tid.bowl byk.bowl `tid %child !>(~)])
185 ==
186;< ~ bind:m (sleep ~s5)
187%- (slog leaf+"Stopping child thread..." ~)
188;< ~ bind:m %- poke-our
189 :* %spider
190 %spider-stop
191 !>([tid %.y])
192 ==
193;< ~ bind:m (sleep ~s2)
194(pure:m !>("Done"))
195```
197#### `child.hoon`
199```hoon
200/- spider
201/+ *strandio
202=, strand=strand:spider
203=>
204|%
205++ looper
206 =/ m (strand ,~)
207 ^- form:m
208 %- (main-loop ,~)
209 :~ |= ~
210 ^- form:m
211 ;< ~ bind:m (sleep `@dr`(div ~s1 2))
212 %- (slog leaf+"child thread" ~)
213 (pure:m ~)
214 ==
215--
216^- thread:spider
217|= arg=vase
218=/ m (strand ,vase)
219^- form:m
220;< ~ bind:m looper
221(pure:m !>(~))
222```
224`child.hoon` just prints to the dojo in a loop.
226`parent.hoon` starts `child.hoon`, and then pokes spider like:
228```hoon
229;< ~ bind:m %- poke-our
230 :* %spider
231 %spider-stop
232 !>([tid %.y])
233 ==
234```
236- `%spider-stop` is the mark that tells spider to kill a thread.
237- `tid` is the tid of the thread to kill
238- `%.y` tells spider to suppress traceback in the result of the killed thread. If you give it `%.n` it will include the traceback.