@@ -41,7 +41,7 @@ Scoped threads in [Crossbeam](https://docs.rs/crossbeam/0.7.1/crossbeam/thread/i
41
41
have matured through years of experience and today we have a design that feels solid
42
42
enough to be promoted into the standard library.
43
43
44
- See the [ rationale- and- alternatives] ( #rationale-and-alternatives ) section for more.
44
+ See the [ Rationale and alternatives] ( #rationale-and-alternatives ) section for more.
45
45
46
46
# Guide-level explanation
47
47
[ guide-level-explanation ] : #guide-level-explanation
@@ -146,46 +146,63 @@ thread::scope(|s| {
146
146
# Reference-level explanation
147
147
[ reference-level-explanation ] : #reference-level-explanation
148
148
149
- We add a single new type to the ` std::thread ` module:
149
+ We add two new types to the ` std::thread ` module:
150
150
151
151
``` 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
153
163
```
154
164
155
165
Next, we need the ` scope() ` and ` spawn() ` functions:
156
166
157
167
``` rust
158
- fn scope <'a , F , T >(f : F ) -> Result <T >
168
+ fn scope <'env , F , T >(f : F ) -> Result <T >
159
169
where
160
- F : FnOnce (& Scope <'a >) -> T ;
170
+ F : FnOnce (& Scope <'env >) -> T ;
161
171
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 >
164
174
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 ;
167
177
}
168
178
```
169
179
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:
172
186
173
187
``` rust
188
+ impl <'scope , T > ScopedJoinHandle <'scope , T > {
189
+ fn join (self ) -> Result <T >;
190
+ fn thread (& self ) -> & Thread ;
191
+ }
192
+
174
193
impl 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 >>
176
199
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 ;
179
202
}
180
203
```
181
204
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
189
206
unjoined threads get automatically joined. If all joins succeed, we take
190
207
the result of the main closure passed to ` scope() ` and wrap it inside ` Ok ` .
191
208
@@ -229,10 +246,7 @@ several advantages to having them in the standard library:
229
246
feels like a missing piece in the standard library.
230
247
231
248
* 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.
236
250
237
251
* There are many examples in the official documentation and books that could be
238
252
simplified by scoped threads.
@@ -242,7 +256,7 @@ several advantages to having them in the standard library:
242
256
This is sometimes a problem in unit tests, where "dangling" threads can accumulate
243
257
if unit tests spawn threads and forget to join them.
244
258
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
246
260
all the time. Having them as a "blessed" pattern in ` std::thread ` would be beneficial
247
261
to everyone.
248
262
@@ -274,8 +288,7 @@ There are several differences between old and new scoped threads:
274
288
non-obvious behavior.
275
289
276
290
4 . ` 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.
279
292
280
293
Rayon also has [ scopes] ( https://docs.rs/rayon/1.0.3/rayon/struct.Scope.html ) ,
281
294
but they work on a different abstraction level - Rayon spawns tasks rather than
0 commit comments