@@ -17,8 +17,7 @@ let var = String::from("foo");
1717thread :: scope (| s | {
1818 s . spawn (| _ | println! (" borrowed from thread #1: {}" , var ));
1919 s . spawn (| _ | println! (" borrowed from thread #2: {}" , var ));
20- })
21- . unwrap ();
20+ });
2221```
2322
2423# Motivation
@@ -81,7 +80,7 @@ handle1.join().unwrap();
8180handle2 . join (). unwrap ();
8281```
8382
84- Scoped threads coming to the rescue! By opening a new ` thread::scope() ` block,
83+ Scoped threads to the rescue! By opening a new ` thread::scope() ` block,
8584we can prove to the compiler that all threads spawned within this scope will
8685also die inside the scope:
8786
@@ -99,8 +98,7 @@ thread::scope(|s| {
9998
10099 handle1 . join (). unwrap ();
101100 handle2 . join (). unwrap ();
102- })
103- . unwrap ();
101+ });
104102```
105103
106104That means variables living outside the scope can be borrowed without any
@@ -120,13 +118,11 @@ thread::scope(|s| {
120118 s . spawn (| _ | {
121119 println! (" thread #2 says: {}" , greeting );
122120 });
123- })
124- . unwrap ();
121+ });
125122```
126123
127- Note that ` thread::scope() ` returns a ` Result ` that will be ` Ok ` if all
128- automatically joined threads have successfully completed, i.e. they haven't
129- panicked.
124+ When taking advantage of automatic joining in this way, note that ` thread::scope() `
125+ will panic if any of the automatically joined threads has panicked.
130126
131127You might've noticed that scoped threads now take a single argument, which is
132128just another reference to ` s ` . Since ` s ` lives inside the scope, we cannot borrow
@@ -139,8 +135,7 @@ thread::scope(|s| {
139135 println! (" I belong to the same `thread::scope()` as my parent thread" )
140136 });
141137 });
142- })
143- . unwrap ();
138+ });
144139```
145140
146141# Reference-level explanation
@@ -165,7 +160,7 @@ inside the scope. The lifetime relations are:
165160Next, we need the ` scope() ` and ` spawn() ` functions:
166161
167162``` rust
168- fn scope <'env , F , T >(f : F ) -> Result < T >
163+ fn scope <'env , F , T >(f : F ) -> T
169164where
170165 F : FnOnce (& Scope <'env >) -> T ;
171166
@@ -202,28 +197,6 @@ impl Builder {
202197}
203198```
204199
205- It's also worth pointing out what exactly happens at the scope end when all
206- unjoined threads get automatically joined. If all joins succeed, we take
207- the result of the main closure passed to ` scope() ` and wrap it inside ` Ok ` .
208-
209- If any thread panics (and in fact multiple threads can panic), we collect
210- all those panics into a ` Vec ` , box it, and finally wrap it inside ` Err ` .
211- The error type is then erased because ` thread::Result<T> ` is just an
212- alias for:
213-
214- ``` rust
215- Result <T , Box <dyn Any + Send + 'static >>
216- ```
217-
218- This way we can do ` thread::scope(...).unwrap() ` to propagate all panics
219- in child threads into the main parent thread.
220-
221- If the main ` scope() ` closure has panicked after spawning threads, we
222- just resume unwinding after joining child threads.
223-
224- Crossbeam's logic for error handling can be found
225- [ here] ( https://github.com/crossbeam-rs/crossbeam/blob/79210d6ae34a3e84b23546d8abc5c4b81b206019/crossbeam-utils/src/thread.rs#L167-L193 ) .
226-
227200# Drawbacks
228201[ drawbacks ] : #drawbacks
229202
@@ -276,9 +249,9 @@ Rust 1.0 era. The new one is from the last year's big revamp:
276249
277250There are several differences between old and new scoped threads:
278251
279- 1 . ` scope() ` now returns a ` thread::Result<T> ` rather than ` T ` . This is because
280- panics in the old design were just silently ignored, which is not good .
281- By returning a ` Result ` , the user can handle panics in whatever way they want .
252+ 1 . ` scope() ` now propagates unhandled panics from child threads.
253+ In the old design, panics were silently ignored.
254+ Users can still handle panics by manually working with ` ScopedJoinHandle ` s .
282255
2832562 . The closure passed to ` Scope::spawn() ` now takes a ` &Scope<'env> ` argument that
284257 allows one to spawn nested threads, which was not possible with the old design.
@@ -292,14 +265,12 @@ There are several differences between old and new scoped threads:
292265
293266Rayon also has [ scopes] ( https://docs.rs/rayon/1.0.3/rayon/struct.Scope.html ) ,
294267but they work on a different abstraction level - Rayon spawns tasks rather than
295- threads. Its API is almost the same as proposed in this RFC, the only
296- difference being that ` scope() ` propagates panics instead of returning ` Result ` .
297- This behavior makes more sense for tasks than threads.
268+ threads. Its API is the same as the one proposed in this RFC.
298269
299270# Unresolved questions
300271[ unresolved-questions ] : #unresolved-questions
301272
302- None.
273+ Can this concept be extended to async? Would there be any behavioral or API differences?
303274
304275# Future possibilities
305276[ future-possibilities ] : #future-possibilities
0 commit comments