@@ -41,7 +41,7 @@ Scoped threads in [Crossbeam](https://docs.rs/crossbeam/0.7.1/crossbeam/thread/i
4141have matured through years of experience and today we have a design that feels solid
4242enough to be promoted into the standard library.
4343
44- See the [ rationale- and- alternatives] ( #rationale-and-alternatives ) section for more.
44+ See the [ Rationale and alternatives] ( #rationale-and-alternatives ) section for more.
4545
4646# Guide-level explanation
4747[ guide-level-explanation ] : #guide-level-explanation
@@ -146,46 +146,63 @@ thread::scope(|s| {
146146# Reference-level explanation
147147[ reference-level-explanation ] : #reference-level-explanation
148148
149- We add a single new type to the ` std::thread ` module:
149+ We add two new types to the ` std::thread ` module:
150150
151151``` rust
152- struct Scope <'a > {}
152+ struct Scope <'env > {}
153+ struct ScopedJoinHandle <'scope , T > {}
154+ ```
155+
156+ Lifetime ` 'env ` represents the environment outside the scope, while
157+ ` 'scope ` represents the scope itself. More precisely, everything
158+ outside the scope outlives ` 'env ` and ` 'scope ` outlives everything
159+ inside the scope. The lifetime relations are:
160+
161+ ```
162+ 'variables_outside: 'env: 'scope: 'variables_inside
153163```
154164
155165Next, we need the ` scope() ` and ` spawn() ` functions:
156166
157167``` rust
158- fn scope <'a , F , T >(f : F ) -> Result <T >
168+ fn scope <'env , F , T >(f : F ) -> Result <T >
159169where
160- F : FnOnce (& Scope <'a >) -> T ;
170+ F : FnOnce (& Scope <'env >) -> T ;
161171
162- impl <'a > Scope <'a > {
163- fn spawn <F , T >(& self , f : F ) -> JoinHandle < T >
172+ impl <'env > Scope <'env > {
173+ fn spawn <' scope , F , T >(& ' scope self , f : F ) -> ScopedJoinHandle <' scope , T >
164174 where
165- F : FnOnce (& Scope <'a >) -> T + Send + 'a ,
166- T : Send + 'a ;
175+ F : FnOnce (& Scope <'env >) -> T + Send + 'env ,
176+ T : Send + 'env ;
167177}
168178```
169179
170- There's just one more thing that will make the API complete: The thread builder
171- needs to be able to spawn threads inside a scope.
180+ That's the gist of scoped threads, really.
181+
182+ Now we just need two more things to make the API complete. First, ` ScopedJoinHandle `
183+ is equivalent to ` JoinHandle ` but tied to the ` 'scope ` lifetime, so it will have
184+ the same methods. Second, the thread builder needs to be able to spawn threads
185+ inside a scope:
172186
173187``` rust
188+ impl <'scope , T > ScopedJoinHandle <'scope , T > {
189+ fn join (self ) -> Result <T >;
190+ fn thread (& self ) -> & Thread ;
191+ }
192+
174193impl Builder {
175- fn spawn_scoped <'a , F , T >(self , scope : & Scope <'a >, f : F ) -> io :: Result <JoinHandle <T >>
194+ fn spawn_scoped <'scope , 'env , F , T >(
195+ self ,
196+ & 'scope Scope <'env >,
197+ f : F ,
198+ ) -> io :: Result <ScopedJoinHandle <'scope , T >>
176199 where
177- F : FnOnce (& Scope <'a >) -> T + Send + 'a ,
178- T : Send + 'a ;
200+ F : FnOnce (& Scope <'env >) -> T + Send + 'env ,
201+ T : Send + 'env ;
179202}
180203```
181204
182- Note that this interface is a bit simpler than the one in Crossbeam
183- because we can now merge ` JoinHandle ` and ` ScopedJoinHandle ` into a single type.
184- Moreover, in Crossbeam, ` ScopedJoinHandle ` is generic over ` 'scope ` , which is
185- not really necessary for soundness so we can remove that lifetime to simplify
186- things further.
187-
188- It's also worth discussing what exactly happens at the scope end when all
205+ It's also worth pointing out what exactly happens at the scope end when all
189206unjoined threads get automatically joined. If all joins succeed, we take
190207the result of the main closure passed to ` scope() ` and wrap it inside ` Ok ` .
191208
@@ -229,10 +246,7 @@ several advantages to having them in the standard library:
229246 feels like a missing piece in the standard library.
230247
231248* Implementing scoped threads is very tricky to get right so it's good to have a
232- reliable solution provided by the standard library. Also, scoped threads in ` libstd `
233- will be simpler because we don't need to introduce a special type for
234- [ scoped join handles] ( https://docs.rs/crossbeam/0.7.1/crossbeam/thread/struct.ScopedJoinHandle.html )
235- or [ builders] ( https://docs.rs/crossbeam/0.7.1/crossbeam/thread/struct.ScopedThreadBuilder.html ) .
249+ reliable solution provided by the standard library.
236250
237251* There are many examples in the official documentation and books that could be
238252 simplified by scoped threads.
@@ -242,7 +256,7 @@ several advantages to having them in the standard library:
242256 This is sometimes a problem in unit tests, where "dangling" threads can accumulate
243257 if unit tests spawn threads and forget to join them.
244258
245- * It's indisputable that users keep asking for scoped threads on IRC and forums
259+ * Users keep asking for scoped threads on IRC and forums
246260 all the time. Having them as a "blessed" pattern in ` std::thread ` would be beneficial
247261 to everyone.
248262
@@ -274,8 +288,7 @@ There are several differences between old and new scoped threads:
274288 non-obvious behavior.
275289
2762904 . ` ScopedJoinHandle ` got parametrized over ` 'scope ` in order to prevent it from
277- escaping the scope. However, it turns out this is not really necessary for
278- soundness and was just a conservative safeguard.
291+ escaping the scope.
279292
280293Rayon also has [ scopes] ( https://docs.rs/rayon/1.0.3/rayon/struct.Scope.html ) ,
281294but they work on a different abstraction level - Rayon spawns tasks rather than
0 commit comments